[jboss-cvs] JBossBlog SVN: r350 - in feeds100P26: docs and 125 other directories.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Thu Mar 26 09:55:24 EDT 2009
Author: sviluppatorefico
Date: 2009-03-26 09:55:24 -0400 (Thu, 26 Mar 2009)
New Revision: 350
Added:
feeds100P26/blog.iml
feeds100P26/build-design.properties
feeds100P26/build-dev.properties
feeds100P26/build-prod.properties
feeds100P26/build.properties
feeds100P26/build.xml
feeds100P26/docs/
feeds100P26/docs/admin_link.png
feeds100P26/docs/group_header.png
feeds100P26/docs/tutorial.html
feeds100P26/lib/
feeds100P26/lib/activation.jar
feeds100P26/lib/ant-antlr.jar
feeds100P26/lib/antlr-runtime.jar
feeds100P26/lib/antlr.jar
feeds100P26/lib/asm-attrs.jar
feeds100P26/lib/asm.jar
feeds100P26/lib/cglib-nodep.jar
feeds100P26/lib/cglib.jar
feeds100P26/lib/commons-beanutils.jar
feeds100P26/lib/commons-collections.jar
feeds100P26/lib/commons-configuration-1.6.jar
feeds100P26/lib/commons-digester.jar
feeds100P26/lib/commons-lang-2.4.jar
feeds100P26/lib/commons-lang.jar
feeds100P26/lib/commons-logging.jar
feeds100P26/lib/core.jar
feeds100P26/lib/dbunit.jar
feeds100P26/lib/dom4j.jar
feeds100P26/lib/drools-compiler.jar
feeds100P26/lib/drools-core.jar
feeds100P26/lib/easymock.jar
feeds100P26/lib/ehcache-1.2.3.jar
feeds100P26/lib/ejb-api.jar
feeds100P26/lib/el-api.jar
feeds100P26/lib/groovy-all.jar
feeds100P26/lib/gwt-servlet.jar
feeds100P26/lib/hibernate-annotations.jar
feeds100P26/lib/hibernate-commons-annotations.jar
feeds100P26/lib/hibernate-entitymanager.jar
feeds100P26/lib/hibernate-search.jar
feeds100P26/lib/hibernate-validator.jar
feeds100P26/lib/hibernate.jar
feeds100P26/lib/hibernate3.jar
feeds100P26/lib/htmlcleaner1_6.jar
feeds100P26/lib/itext.jar
feeds100P26/lib/janino.jar
feeds100P26/lib/javassist.jar
feeds100P26/lib/jaxb-api.jar
feeds100P26/lib/jaxws-api.jar
feeds100P26/lib/jboss-aop.jar
feeds100P26/lib/jboss-cache.jar
feeds100P26/lib/jboss-common-core.jar
feeds100P26/lib/jboss-dependency.jar
feeds100P26/lib/jboss-deployers-client-spi.jar
feeds100P26/lib/jboss-deployers-core-spi.jar
feeds100P26/lib/jboss-el.jar
feeds100P26/lib/jboss-embedded-api.jar
feeds100P26/lib/jboss-jmx.jar
feeds100P26/lib/jboss-kernel.jar
feeds100P26/lib/jboss-logging-spi.jar
feeds100P26/lib/jboss-seam-debug.jar
feeds100P26/lib/jboss-seam-gen.jar
feeds100P26/lib/jboss-seam-ioc.jar
feeds100P26/lib/jboss-seam-mail.jar
feeds100P26/lib/jboss-seam-pdf.jar
feeds100P26/lib/jboss-seam-remoting.jar
feeds100P26/lib/jboss-seam-ui.jar
feeds100P26/lib/jboss-seam.jar
feeds100P26/lib/jboss-system.jar
feeds100P26/lib/jbossxb.jar
feeds100P26/lib/jbpm-jpdl.jar
feeds100P26/lib/jcommon.jar
feeds100P26/lib/jdom.jar
feeds100P26/lib/jericho-html-2.5.jar
feeds100P26/lib/jfreechart.jar
feeds100P26/lib/jgroups.jar
feeds100P26/lib/jms.jar
feeds100P26/lib/jsf-api.jar
feeds100P26/lib/jsf-facelets.jar
feeds100P26/lib/jsf-impl.jar
feeds100P26/lib/jsp-api.jar
feeds100P26/lib/jsr173_api.jar
feeds100P26/lib/jsr181-api.jar
feeds100P26/lib/jsr250-api.jar
feeds100P26/lib/jstl.jar
feeds100P26/lib/jta.jar
feeds100P26/lib/let-tag.jar
feeds100P26/lib/log4j.jar
feeds100P26/lib/lucene-core.jar
feeds100P26/lib/mail.jar
feeds100P26/lib/meldware-mailapi.jar
feeds100P26/lib/meldware-mailjmx.jar
feeds100P26/lib/mvel14.jar
feeds100P26/lib/mysql.jar
feeds100P26/lib/persistence-api.jar
feeds100P26/lib/portal-common-lib.jar
feeds100P26/lib/portal-identity-lib.jar
feeds100P26/lib/portal-portlet-jsr168api-lib.jar
feeds100P26/lib/portlet-api.jar
feeds100P26/lib/richfaces-api.jar
feeds100P26/lib/richfaces-impl.jar
feeds100P26/lib/richfaces-ui.jar
feeds100P26/lib/rome-1.0RC1.jar
feeds100P26/lib/saaj-api.jar
feeds100P26/lib/servlet-api.jar
feeds100P26/lib/shotoku-base.jar
feeds100P26/lib/spring.jar
feeds100P26/lib/src/
feeds100P26/lib/src/jboss-seam-debug-sources.jar
feeds100P26/lib/src/jboss-seam-gen-sources.jar
feeds100P26/lib/src/jboss-seam-ioc-sources.jar
feeds100P26/lib/src/jboss-seam-mail-sources.jar
feeds100P26/lib/src/jboss-seam-pdf-sources.jar
feeds100P26/lib/src/jboss-seam-remoting-sources.jar
feeds100P26/lib/src/jboss-seam-sources.jar
feeds100P26/lib/src/jboss-seam-ui-sources.jar
feeds100P26/lib/standard.jar
feeds100P26/lib/test/
feeds100P26/lib/test/hibernate-all.jar
feeds100P26/lib/test/jboss-embedded-all.jar
feeds100P26/lib/test/thirdparty-all.jar
feeds100P26/lib/testng.jar
feeds100P26/lib/urlrewritefilter.jar
feeds100P26/lib/velocity-1.5.jar
feeds100P26/lib/velocity-dep-1.5.jar
feeds100P26/resources-portlet/
feeds100P26/resources-portlet/WEB-INF/
feeds100P26/resources-portlet/WEB-INF/blog-object.xml
feeds100P26/resources-portlet/WEB-INF/jboss-app.xml
feeds100P26/resources-portlet/WEB-INF/jboss-portlet.xml
feeds100P26/resources-portlet/WEB-INF/portlet-instances.xml
feeds100P26/resources-portlet/WEB-INF/portlet.xml
feeds100P26/resources-portlet/WEB-INF/web.xml
feeds100P26/resources/
feeds100P26/resources/META-INF/
feeds100P26/resources/META-INF/application.xml
feeds100P26/resources/META-INF/ejb-jar.xml
feeds100P26/resources/META-INF/jboss-app.xml
feeds100P26/resources/META-INF/jbossblog.taglib.xml
feeds100P26/resources/META-INF/persistence-design.xml
feeds100P26/resources/META-INF/persistence-dev.xml
feeds100P26/resources/META-INF/persistence-prod.xml
feeds100P26/resources/META-INF/security.drl
feeds100P26/resources/WEB-INF/
feeds100P26/resources/WEB-INF/components.xml
feeds100P26/resources/WEB-INF/faces-config.xml
feeds100P26/resources/WEB-INF/pages.xml
feeds100P26/resources/WEB-INF/urlrewrite.xml
feeds100P26/resources/WEB-INF/web-design.xml
feeds100P26/resources/WEB-INF/web-dev.xml
feeds100P26/resources/WEB-INF/web-prod.xml
feeds100P26/resources/blog-design-ds.xml
feeds100P26/resources/blog-dev-ds.xml
feeds100P26/resources/blog-ehcache.xml
feeds100P26/resources/blog-prod-ds.xml
feeds100P26/resources/components.properties
feeds100P26/resources/messages_en.properties
feeds100P26/resources/seam.properties
feeds100P26/resources/templates/
feeds100P26/resources/templates/atom_standard.vm
feeds100P26/resources/templates/rss1_standard.vm
feeds100P26/resources/templates/rss2_standard.vm
feeds100P26/resources/velocity.properties
feeds100P26/src/
feeds100P26/src/action/
feeds100P26/src/action/org/
feeds100P26/src/action/org/jboss/
feeds100P26/src/action/org/jboss/blog/
feeds100P26/src/action/org/jboss/blog/servlet/
feeds100P26/src/action/org/jboss/blog/servlet/FeedsServlet.java
feeds100P26/src/action/org/jboss/blog/session/
feeds100P26/src/action/org/jboss/blog/session/cache/
feeds100P26/src/action/org/jboss/blog/session/cache/CacheManager.java
feeds100P26/src/action/org/jboss/blog/session/cache/CacheManagerHashMapImpl.java
feeds100P26/src/action/org/jboss/blog/session/cache/FeedsChangesObserver.java
feeds100P26/src/action/org/jboss/blog/session/category/
feeds100P26/src/action/org/jboss/blog/session/category/CategoryServiceBean.java
feeds100P26/src/action/org/jboss/blog/session/configuration/
feeds100P26/src/action/org/jboss/blog/session/configuration/ConfigurationManager.java
feeds100P26/src/action/org/jboss/blog/session/converter/
feeds100P26/src/action/org/jboss/blog/session/converter/FeedConverter.java
feeds100P26/src/action/org/jboss/blog/session/converter/GroupConverter.java
feeds100P26/src/action/org/jboss/blog/session/converter/PostConverter.java
feeds100P26/src/action/org/jboss/blog/session/converter/TemplateConverter.java
feeds100P26/src/action/org/jboss/blog/session/exceptions/
feeds100P26/src/action/org/jboss/blog/session/exceptions/FeedNotFoundRuntimeException.java
feeds100P26/src/action/org/jboss/blog/session/exceptions/PostNotFoundRuntimeException.java
feeds100P26/src/action/org/jboss/blog/session/feed/
feeds100P26/src/action/org/jboss/blog/session/feed/FeedsServiceImpl.java
feeds100P26/src/action/org/jboss/blog/session/feed/InvalidFeedTypeException.java
feeds100P26/src/action/org/jboss/blog/session/feed/dao/
feeds100P26/src/action/org/jboss/blog/session/feed/dao/AggregatedFeedDao.java
feeds100P26/src/action/org/jboss/blog/session/feed/dao/FeedDao.java
feeds100P26/src/action/org/jboss/blog/session/feed/dao/HighlightsFeedDao.java
feeds100P26/src/action/org/jboss/blog/session/feed/dao/IndividualPostsFeedDao.java
feeds100P26/src/action/org/jboss/blog/session/feed/dao/RemoteFeedDao.java
feeds100P26/src/action/org/jboss/blog/session/feed/lock/
feeds100P26/src/action/org/jboss/blog/session/feed/lock/FeedsLocksBean.java
feeds100P26/src/action/org/jboss/blog/session/feed/mod/
feeds100P26/src/action/org/jboss/blog/session/feed/mod/AggregatedDeleteListener.java
feeds100P26/src/action/org/jboss/blog/session/feed/mod/AggregatedFeedModBean.java
feeds100P26/src/action/org/jboss/blog/session/feed/mod/FeedModBean.java
feeds100P26/src/action/org/jboss/blog/session/feed/mod/FilterAddBean.java
feeds100P26/src/action/org/jboss/blog/session/feed/mod/HighlightsDeleteListener.java
feeds100P26/src/action/org/jboss/blog/session/feed/mod/HighlightsFeedModBean.java
feeds100P26/src/action/org/jboss/blog/session/feed/mod/IndividualFeedModBean.java
feeds100P26/src/action/org/jboss/blog/session/feed/mod/PostsValidator.java
feeds100P26/src/action/org/jboss/blog/session/feed/mod/PropositionsListener.java
feeds100P26/src/action/org/jboss/blog/session/feed/mod/PropositionsToolsBean.java
feeds100P26/src/action/org/jboss/blog/session/feed/mod/RemoteFeedModBean.java
feeds100P26/src/action/org/jboss/blog/session/feed/posts/
feeds100P26/src/action/org/jboss/blog/session/feed/posts/AggregatedFeedPosts.java
feeds100P26/src/action/org/jboss/blog/session/feed/posts/AggregatedFeedStack.java
feeds100P26/src/action/org/jboss/blog/session/feed/posts/DatabaseFeedPosts.java
feeds100P26/src/action/org/jboss/blog/session/feed/type/
feeds100P26/src/action/org/jboss/blog/session/feed/type/FeedType.java
feeds100P26/src/action/org/jboss/blog/session/feed/type/FeedTypes.java
feeds100P26/src/action/org/jboss/blog/session/feed/update/
feeds100P26/src/action/org/jboss/blog/session/feed/update/IndividualPostsFeedUpdate.java
feeds100P26/src/action/org/jboss/blog/session/feed/update/RemoteFeedUpdate.java
feeds100P26/src/action/org/jboss/blog/session/group/
feeds100P26/src/action/org/jboss/blog/session/group/GroupModBean.java
feeds100P26/src/action/org/jboss/blog/session/group/GroupsServiceImpl.java
feeds100P26/src/action/org/jboss/blog/session/merge/
feeds100P26/src/action/org/jboss/blog/session/merge/FeedsServicePostsIterator.java
feeds100P26/src/action/org/jboss/blog/session/merge/ListPostsIterator.java
feeds100P26/src/action/org/jboss/blog/session/merge/MergeServiceBean.java
feeds100P26/src/action/org/jboss/blog/session/merge/PostManager.java
feeds100P26/src/action/org/jboss/blog/session/merge/PostsIterator.java
feeds100P26/src/action/org/jboss/blog/session/merge/TitleAsIdService.java
feeds100P26/src/action/org/jboss/blog/session/merge/TitleAsIdServiceBean.java
feeds100P26/src/action/org/jboss/blog/session/parser/
feeds100P26/src/action/org/jboss/blog/session/parser/ParserException.java
feeds100P26/src/action/org/jboss/blog/session/parser/ParserService.java
feeds100P26/src/action/org/jboss/blog/session/parser/ParserServiceImpl.java
feeds100P26/src/action/org/jboss/blog/session/scanner/
feeds100P26/src/action/org/jboss/blog/session/scanner/AnnotationScanner.java
feeds100P26/src/action/org/jboss/blog/session/scanner/ClassHandler.java
feeds100P26/src/action/org/jboss/blog/session/scanner/Init.java
feeds100P26/src/action/org/jboss/blog/session/search/
feeds100P26/src/action/org/jboss/blog/session/search/PostSearchBean.java
feeds100P26/src/action/org/jboss/blog/session/search/SearchReindexObserver.java
feeds100P26/src/action/org/jboss/blog/session/security/
feeds100P26/src/action/org/jboss/blog/session/security/Authenticator.java
feeds100P26/src/action/org/jboss/blog/session/security/FeedsCombinedRole.java
feeds100P26/src/action/org/jboss/blog/session/security/FeedsIdentity.java
feeds100P26/src/action/org/jboss/blog/session/security/InvalidLoginException.java
feeds100P26/src/action/org/jboss/blog/session/security/RestrictedKeyGenerator.java
feeds100P26/src/action/org/jboss/blog/session/security/SecurityGroupConverter.java
feeds100P26/src/action/org/jboss/blog/session/security/SecurityModBean.java
feeds100P26/src/action/org/jboss/blog/session/security/SecurityObserver.java
feeds100P26/src/action/org/jboss/blog/session/security/SecurityRoleConverter.java
feeds100P26/src/action/org/jboss/blog/session/security/SecurityUserConverter.java
feeds100P26/src/action/org/jboss/blog/session/security/SecurityUserKeys.java
feeds100P26/src/action/org/jboss/blog/session/security/SecurityUserSelectBean.java
feeds100P26/src/action/org/jboss/blog/session/security/external/
feeds100P26/src/action/org/jboss/blog/session/security/external/AbstractExternalSecurityService.java
feeds100P26/src/action/org/jboss/blog/session/security/external/DummyExternalSecurityService.java
feeds100P26/src/action/org/jboss/blog/session/security/external/ExternalSecurityService.java
feeds100P26/src/action/org/jboss/blog/session/security/filtering/
feeds100P26/src/action/org/jboss/blog/session/security/filtering/FeedsSecurity.java
feeds100P26/src/action/org/jboss/blog/session/security/filtering/GroupsSecurity.java
feeds100P26/src/action/org/jboss/blog/session/security/filtering/HighlightsSecurity.java
feeds100P26/src/action/org/jboss/blog/session/security/tools/
feeds100P26/src/action/org/jboss/blog/session/security/tools/FeedSecurityTools.java
feeds100P26/src/action/org/jboss/blog/session/tools/
feeds100P26/src/action/org/jboss/blog/session/tools/AdminBean.java
feeds100P26/src/action/org/jboss/blog/session/tools/CaptchaToolsBean.java
feeds100P26/src/action/org/jboss/blog/session/tools/PostToToolsBean.java
feeds100P26/src/action/org/jboss/blog/session/tools/StringToolsBean.java
feeds100P26/src/action/org/jboss/blog/session/update/
feeds100P26/src/action/org/jboss/blog/session/update/UpdateException.java
feeds100P26/src/action/org/jboss/blog/session/update/UpdateHandler.java
feeds100P26/src/action/org/jboss/blog/session/update/UpdateHandlerAsync.java
feeds100P26/src/action/org/jboss/blog/session/update/UpdateHandlerAsyncImpl.java
feeds100P26/src/action/org/jboss/blog/session/update/UpdateManager.java
feeds100P26/src/action/org/jboss/blog/session/update/UpdateThread.java
feeds100P26/src/action/org/jboss/blog/session/validator/
feeds100P26/src/action/org/jboss/blog/session/validator/UniqueFeedNameValidator.java
feeds100P26/src/action/org/jboss/blog/session/validator/UniqueGroupNameValidator.java
feeds100P26/src/action/org/jboss/blog/session/validator/UniqueTemplateNameValidator.java
feeds100P26/src/action/org/jboss/blog/session/view/
feeds100P26/src/action/org/jboss/blog/session/view/FeedViewBean.java
feeds100P26/src/action/org/jboss/blog/session/view/LinkServiceImpl.java
feeds100P26/src/action/org/jboss/blog/session/view/PostViewBean.java
feeds100P26/src/action/org/jboss/blog/session/xml/
feeds100P26/src/action/org/jboss/blog/session/xml/XmlService.java
feeds100P26/src/action/org/jboss/blog/session/xml/content/
feeds100P26/src/action/org/jboss/blog/session/xml/content/ContentResponse.java
feeds100P26/src/action/org/jboss/blog/session/xml/content/InMemoryContentResponse.java
feeds100P26/src/action/org/jboss/blog/session/xml/content/ServletResponseContentResponse.java
feeds100P26/src/action/org/jboss/blog/session/xml/velocity/
feeds100P26/src/action/org/jboss/blog/session/xml/velocity/DatabaseResourceLoader.java
feeds100P26/src/action/org/jboss/blog/session/xml/velocity/InvalidTemplateTypeException.java
feeds100P26/src/action/org/jboss/blog/session/xml/velocity/TemplateBootstrap.java
feeds100P26/src/action/org/jboss/blog/session/xml/velocity/TemplateModBean.java
feeds100P26/src/action/org/jboss/blog/session/xml/velocity/TemplateServiceBean.java
feeds100P26/src/action/org/jboss/blog/session/xml/velocity/VelocityXmlService.java
feeds100P26/src/action/org/jboss/blog/session/xml/velocity/tools/
feeds100P26/src/action/org/jboss/blog/session/xml/velocity/tools/AtomXmlTools.java
feeds100P26/src/action/org/jboss/blog/session/xml/velocity/tools/Rss1XmlTools.java
feeds100P26/src/action/org/jboss/blog/session/xml/velocity/tools/Rss2XmlTools.java
feeds100P26/src/action/org/jboss/blog/session/xml/velocity/tools/XmlTools.java
feeds100P26/src/action/org/jboss/blog/tools/
feeds100P26/src/action/org/jboss/blog/tools/PostFilterTools.java
feeds100P26/src/action/org/jboss/shotoku/
feeds100P26/src/action/org/jboss/shotoku/web/
feeds100P26/src/action/org/jboss/shotoku/web/FilesystemResourceResolver.java
feeds100P26/src/action/org/jboss/shotoku/web/ResourcesFilter.java
feeds100P26/src/model/
feeds100P26/src/model/org/
feeds100P26/src/model/org/jboss/
feeds100P26/src/model/org/jboss/blog/
feeds100P26/src/model/org/jboss/blog/model/
feeds100P26/src/model/org/jboss/blog/model/Category.java
feeds100P26/src/model/org/jboss/blog/model/Enclosure.java
feeds100P26/src/model/org/jboss/blog/model/Group.java
feeds100P26/src/model/org/jboss/blog/model/Image.java
feeds100P26/src/model/org/jboss/blog/model/Post.java
feeds100P26/src/model/org/jboss/blog/model/RestrictedCategory.java
feeds100P26/src/model/org/jboss/blog/model/RestrictedEnclosure.java
feeds100P26/src/model/org/jboss/blog/model/RestrictedImage.java
feeds100P26/src/model/org/jboss/blog/model/RestrictedPost.java
feeds100P26/src/model/org/jboss/blog/model/Template.java
feeds100P26/src/model/org/jboss/blog/model/XmlType.java
feeds100P26/src/model/org/jboss/blog/model/configuration/
feeds100P26/src/model/org/jboss/blog/model/configuration/Configuration.java
feeds100P26/src/model/org/jboss/blog/model/feed/
feeds100P26/src/model/org/jboss/blog/model/feed/AggregatedFeed.java
feeds100P26/src/model/org/jboss/blog/model/feed/Feed.java
feeds100P26/src/model/org/jboss/blog/model/feed/HighlightsFeed.java
feeds100P26/src/model/org/jboss/blog/model/feed/IndividualPostInfo.java
feeds100P26/src/model/org/jboss/blog/model/feed/IndividualPostsFeed.java
feeds100P26/src/model/org/jboss/blog/model/feed/PostAuthorType.java
feeds100P26/src/model/org/jboss/blog/model/feed/RemoteFeed.java
feeds100P26/src/model/org/jboss/blog/model/feed/RestrictedFeed.java
feeds100P26/src/model/org/jboss/blog/model/log/
feeds100P26/src/model/org/jboss/blog/model/log/PropositionsLog.java
feeds100P26/src/model/org/jboss/blog/model/post/
feeds100P26/src/model/org/jboss/blog/model/post/PostFilter.java
feeds100P26/src/model/org/jboss/blog/model/post/filter/
feeds100P26/src/model/org/jboss/blog/model/post/filter/AbstractRegexpFilter.java
feeds100P26/src/model/org/jboss/blog/model/post/filter/AndFilter.java
feeds100P26/src/model/org/jboss/blog/model/post/filter/AuthorRegexpFilter.java
feeds100P26/src/model/org/jboss/blog/model/post/filter/CategoryRegexpFilter.java
feeds100P26/src/model/org/jboss/blog/model/post/filter/NotPodcastFilter.java
feeds100P26/src/model/org/jboss/blog/model/post/filter/PodcastFilter.java
feeds100P26/src/model/org/jboss/blog/model/post/filter/TotalFilter.java
feeds100P26/src/model/org/jboss/blog/model/security/
feeds100P26/src/model/org/jboss/blog/model/security/FeedsSecurityRole.java
feeds100P26/src/model/org/jboss/blog/model/security/RestrictedSecurityGroup.java
feeds100P26/src/model/org/jboss/blog/model/security/RestrictedSecurityUser.java
feeds100P26/src/model/org/jboss/blog/model/security/SecurityGroup.java
feeds100P26/src/model/org/jboss/blog/model/security/SecurityMapping.java
feeds100P26/src/model/org/jboss/blog/model/security/SecurityUser.java
feeds100P26/src/portal/
feeds100P26/src/portal/org/
feeds100P26/src/portal/org/jboss/
feeds100P26/src/portal/org/jboss/blog/
feeds100P26/src/portal/org/jboss/blog/portlet/
feeds100P26/src/portal/org/jboss/blog/portlet/BlogPortlet.java
feeds100P26/src/portal/org/jboss/blog/session/
feeds100P26/src/portal/org/jboss/blog/session/security/
feeds100P26/src/portal/org/jboss/blog/session/security/external/
feeds100P26/src/portal/org/jboss/blog/session/security/external/PortalExternalSecurityService.java
feeds100P26/src/portal/org/jboss/blog/session/security/external/PortalRole.java
feeds100P26/src/portal/org/jboss/blog/session/security/external/PortalSecurityException.java
feeds100P26/src/portal/org/jboss/blog/session/security/external/PortalSecurityService.java
feeds100P26/src/portal/org/jboss/blog/session/security/external/PortalSecurityServiceImpl.java
feeds100P26/src/portal/org/jboss/blog/session/security/external/PortalUser.java
feeds100P26/src/portal/org/jboss/blog/session/security/external/SecurityBootstrap.java
feeds100P26/src/services/
feeds100P26/src/services/org/
feeds100P26/src/services/org/jboss/
feeds100P26/src/services/org/jboss/blog/
feeds100P26/src/services/org/jboss/blog/service/
feeds100P26/src/services/org/jboss/blog/service/FeedNotFoundException.java
feeds100P26/src/services/org/jboss/blog/service/FeedsService.java
feeds100P26/src/services/org/jboss/blog/service/GroupsService.java
feeds100P26/src/services/org/jboss/blog/service/LinkService.java
feeds100P26/src/services/org/jboss/blog/service/PostNotFoundException.java
feeds100P26/src/shotoku/
feeds100P26/src/shotoku/org/
feeds100P26/src/shotoku/org/jboss/
feeds100P26/src/shotoku/org/jboss/blog/
feeds100P26/src/shotoku/org/jboss/blog/model/
feeds100P26/src/shotoku/org/jboss/blog/model/shotoku/
feeds100P26/src/shotoku/org/jboss/blog/model/shotoku/ShotokuFeed.java
feeds100P26/src/shotoku/org/jboss/blog/session/
feeds100P26/src/shotoku/org/jboss/blog/session/feed/
feeds100P26/src/shotoku/org/jboss/blog/session/feed/dao/
feeds100P26/src/shotoku/org/jboss/blog/session/feed/dao/ShotokuFeedDao.java
feeds100P26/src/shotoku/org/jboss/blog/session/feed/mod/
feeds100P26/src/shotoku/org/jboss/blog/session/feed/mod/ShotokuModBean.java
feeds100P26/src/shotoku/org/jboss/blog/session/feed/update/
feeds100P26/src/shotoku/org/jboss/blog/session/feed/update/ShotokuFeedUpdate.java
feeds100P26/src/shotoku/org/jboss/blog/session/shotoku/
feeds100P26/src/shotoku/org/jboss/blog/session/shotoku/PostContentTooLargeException.java
feeds100P26/src/shotoku/org/jboss/blog/session/shotoku/ShotokuException.java
feeds100P26/src/shotoku/org/jboss/blog/session/shotoku/ShotokuFeedService.java
feeds100P26/src/shotoku/org/jboss/shotoku/
feeds100P26/src/shotoku/org/jboss/shotoku/web/
feeds100P26/src/shotoku/org/jboss/shotoku/web/ShotokuFilesystemResourceResolver.java
feeds100P26/src/shotoku/org/jboss/shotoku/web/ShotokuResourcesFilter.java
feeds100P26/src/test/
feeds100P26/src/test/org/
feeds100P26/src/test/org/jboss/
feeds100P26/src/test/org/jboss/blog/
feeds100P26/src/test/org/jboss/blog/session/
feeds100P26/src/test/org/jboss/blog/session/feed/
feeds100P26/src/test/org/jboss/blog/session/feed/posts/
feeds100P26/src/test/org/jboss/blog/session/feed/posts/AggregatedFeedPostsTest.java
feeds100P26/src/test/org/jboss/blog/session/merge/
feeds100P26/src/test/org/jboss/blog/session/merge/test/
feeds100P26/src/test/org/jboss/blog/session/merge/test/GenericsExample1.java
feeds100P26/src/test/org/jboss/blog/session/merge/test/MergeServiceTest.java
feeds100P26/src/test/org/jboss/blog/session/merge/test/MockEvents.java
feeds100P26/src/test/org/jboss/blog/session/merge/test/MockTitleAsIdService.java
feeds100P26/src/test/org/jboss/blog/session/parser/
feeds100P26/src/test/org/jboss/blog/session/parser/RomeExample.java
feeds100P26/src/test/org/jboss/blog/session/parser/RomeExample2.java
feeds100P26/src/test/org/jboss/blog/session/parser/RomeExample3.java
feeds100P26/src/test/org/jboss/blog/tools/
feeds100P26/src/test/org/jboss/blog/tools/FixHtmlExample1.java
feeds100P26/src/test/org/jboss/blog/tools/FixHtmlTest.java
feeds100P26/src/test/org/jboss/blog/tools/StripHtmlTest.java
feeds100P26/src/test/org/jboss/blog/tools/TestTools.java
feeds100P26/src/test/org/jboss/blog/tools/TitleToLinkTest.java
feeds100P26/src/tools/
feeds100P26/src/tools/org/
feeds100P26/src/tools/org/jboss/
feeds100P26/src/tools/org/jboss/blog/
feeds100P26/src/tools/org/jboss/blog/tools/
feeds100P26/src/tools/org/jboss/blog/tools/GeneralTools.java
feeds100P26/src/tools/org/jboss/blog/tools/KeyNotMappedException.java
feeds100P26/src/tools/org/jboss/blog/tools/KeySafeMap.java
feeds100P26/src/tools/org/jboss/blog/tools/Pair.java
feeds100P26/src/tools/org/jboss/blog/tools/StringTools.java
feeds100P26/src/tools/org/jboss/blog/tools/search/
feeds100P26/src/tools/org/jboss/blog/tools/search/UnrestrictedFeedFilter.java
feeds100P26/src/tools/org/jboss/blog/tools/search/bridge/
feeds100P26/src/tools/org/jboss/blog/tools/search/bridge/FeedBridge.java
feeds100P26/src/tools/org/jboss/blog/tools/search/bridge/StripHtmlBridge.java
feeds100P26/src/tools/org/jboss/blog/tools/validator/
feeds100P26/src/tools/org/jboss/blog/tools/validator/Regexp.java
feeds100P26/src/tools/org/jboss/blog/tools/validator/RegexpValidator.java
feeds100P26/view-portlet/
feeds100P26/view-portlet/feed_not_found.jsp
feeds100P26/view-portlet/view.jsp
feeds100P26/view-portlet/view_main.jsp
feeds100P26/view/
feeds100P26/view/common/
feeds100P26/view/common/ajax_status.xhtml
feeds100P26/view/common/next_previous_navigation.xhtml
feeds100P26/view/common/post.xhtml
feeds100P26/view/emails/
feeds100P26/view/emails/new_proposition_email.xhtml
feeds100P26/view/emails/proposition_accepted.xhtml
feeds100P26/view/emails/proposition_rejected.xhtml
feeds100P26/view/emails/test_email.xhtml
feeds100P26/view/error/
feeds100P26/view/error/error.xhtml
feeds100P26/view/error/feed_error.xhtml
feeds100P26/view/error/post_error.xhtml
feeds100P26/view/home.xhtml
feeds100P26/view/images/
feeds100P26/view/images/hdr_feed_gradient.gif
feeds100P26/view/images/ico_linkarrow_blue.gif
feeds100P26/view/images/portlethdr_home.gif
feeds100P26/view/images/propose_blog.png
feeds100P26/view/images/propose_blog_full.png
feeds100P26/view/images/wait.gif
feeds100P26/view/index.html
feeds100P26/view/layout/
feeds100P26/view/layout/menu.xhtml
feeds100P26/view/layout/template.xhtml
feeds100P26/view/manage/
feeds100P26/view/manage/aggregated/
feeds100P26/view/manage/aggregated/aggregated_add.xhtml
feeds100P26/view/manage/aggregated/aggregated_edit.xhtml
feeds100P26/view/manage/aggregated/aggregated_mod.xhtml
feeds100P26/view/manage/aggregated/filter_add.xhtml
feeds100P26/view/manage/configuration_manager.xhtml
feeds100P26/view/manage/feed_add.xhtml
feeds100P26/view/manage/feed_edit.xhtml
feeds100P26/view/manage/feed_mod.xhtml
feeds100P26/view/manage/feed_propose.xhtml
feeds100P26/view/manage/group/
feeds100P26/view/manage/group/group_add.xhtml
feeds100P26/view/manage/group/group_edit.xhtml
feeds100P26/view/manage/group/group_list.xhtml
feeds100P26/view/manage/group/group_mod.xhtml
feeds100P26/view/manage/highlights/
feeds100P26/view/manage/highlights/highlights_edit.xhtml
feeds100P26/view/manage/highlights/highlights_mod.xhtml
feeds100P26/view/manage/highlights/post_add.xhtml
feeds100P26/view/manage/index.xhtml
feeds100P26/view/manage/individual/
feeds100P26/view/manage/individual/individual_add.xhtml
feeds100P26/view/manage/individual/individual_edit.xhtml
feeds100P26/view/manage/individual/post_add.xhtml
feeds100P26/view/manage/proposition/
feeds100P26/view/manage/proposition/proposition_accept_1.xhtml
feeds100P26/view/manage/proposition/proposition_accept_2.xhtml
feeds100P26/view/manage/proposition/proposition_list.xhtml
feeds100P26/view/manage/remote/
feeds100P26/view/manage/remote/remote_add.xhtml
feeds100P26/view/manage/remote/remote_edit.xhtml
feeds100P26/view/manage/remote/remote_mod.xhtml
feeds100P26/view/manage/remote/remote_propose.xhtml
feeds100P26/view/manage/shotoku/
feeds100P26/view/manage/shotoku/shotoku_add.page.xml
feeds100P26/view/manage/shotoku/shotoku_add.xhtml
feeds100P26/view/manage/shotoku/shotoku_edit.page.xml
feeds100P26/view/manage/shotoku/shotoku_edit.xhtml
feeds100P26/view/manage/shotoku/shotoku_mod.xhtml
feeds100P26/view/manage/template/
feeds100P26/view/manage/template/template_add.xhtml
feeds100P26/view/manage/template/template_edit.xhtml
feeds100P26/view/manage/template/template_list.xhtml
feeds100P26/view/manage/template/template_mod.xhtml
feeds100P26/view/manage/update_manager.xhtml
feeds100P26/view/search/
feeds100P26/view/search/search.xhtml
feeds100P26/view/security/
feeds100P26/view/security/account.xhtml
feeds100P26/view/security/login.xhtml
feeds100P26/view/security/security_group_add.xhtml
feeds100P26/view/security/security_manager.xhtml
feeds100P26/view/security/security_user_add.xhtml
feeds100P26/view/stylesheet/
feeds100P26/view/stylesheet/blog.css
feeds100P26/view/stylesheet/org_layout.css
feeds100P26/view/stylesheet/org_main.css
feeds100P26/view/view/
feeds100P26/view/view/feed.xhtml
feeds100P26/view/view/feed_toolbar.xhtml
feeds100P26/view/view/post.xhtml
feeds100P26/view/view/right_box.xhtml
Modified:
feeds100P26/
Log:
Property changes on: feeds100P26
___________________________________________________________________
Name: svn:ignore
+ dist
exploded-archives
.project
Added: feeds100P26/blog.iml
===================================================================
--- feeds100P26/blog.iml (rev 0)
+++ feeds100P26/blog.iml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,549 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module relativePaths="true" type="JAVA_MODULE" version="4">
+ <component name="FacetManager">
+ <facet type="jpa" name="JPA">
+ <configuration>
+ <setting name="validation-enabled" value="true" />
+ <setting name="provider-name" value="Hibernate" />
+ <datasource-mapping>
+ <factory-entry name="blog" value="Datasource" />
+ </datasource-mapping>
+ <deploymentDescriptor name="persistence.xml" url="file://$MODULE_DIR$/resources/META-INF/persistence-dev.xml" optional="false" version="1.0" />
+ </configuration>
+ </facet>
+ <facet type="hibernate" name="Hibernate">
+ <configuration>
+ <setting name="validation-enabled" value="true" />
+ <datasource-map />
+ </configuration>
+ </facet>
+ <facet type="javaeeApplication" name="javaEEApplication">
+ <configuration>
+ <descriptors>
+ <deploymentDescriptor name="application.xml" url="file://$MODULE_DIR$/resources/META-INF/application.xml" optional="false" version="5" />
+ </descriptors>
+ <building>
+ <setting name="EXPLODED_URL" value="file://" />
+ <setting name="EXPLODED_ENABLED" value="false" />
+ <setting name="JAR_URL" value="file://" />
+ <setting name="JAR_ENABLED" value="false" />
+ <setting name="BUILD_MODULE_ON_FRAME_DEACTIVATION" value="false" />
+ <setting name="BUILD_EXTERNAL_DEPENDENCIES" value="false" />
+ <setting name="EXCLUDE_EXPLODED_DIRECTORY" value="true" />
+ </building>
+ <packaging>
+ <containerElement type="facet" facetId="blog/ejb/EJB">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="<N/A>" />
+ </containerElement>
+ <containerElement type="facet" facetId="blog/web/Web">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="<N/A>" />
+ <attribute name="contextRoot" value="blogWeb" />
+ </containerElement>
+ <containerElement type="facet" facetId="seam-sources/javaeeApplication/javaEEApplication">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="<N/A>" />
+ </containerElement>
+ </packaging>
+ </configuration>
+ </facet>
+ <facet type="ejb" name="EJB">
+ <configuration>
+ <descriptors>
+ <deploymentDescriptor name="ejb-jar.xml" url="file://$MODULE_DIR$/resources/META-INF/ejb-jar.xml" optional="false" version="3.0" />
+ </descriptors>
+ <ejbRoots>
+ <root url="file://$MODULE_DIR$/src/action" />
+ <root url="file://$MODULE_DIR$/src/model" />
+ <root url="file://$MODULE_DIR$/src/portal" />
+ <root url="file://$MODULE_DIR$/src/services" />
+ <root url="file://$MODULE_DIR$/src/shotoku" />
+ <root url="file://$MODULE_DIR$/src/test" />
+ <root url="file://$MODULE_DIR$/src/tools" />
+ </ejbRoots>
+ <building>
+ <setting name="EXPLODED_URL" value="file://" />
+ <setting name="EXPLODED_ENABLED" value="false" />
+ <setting name="JAR_URL" value="file://" />
+ <setting name="JAR_ENABLED" value="false" />
+ <setting name="BUILD_MODULE_ON_FRAME_DEACTIVATION" value="false" />
+ <setting name="BUILD_EXTERNAL_DEPENDENCIES" value="false" />
+ <setting name="EXCLUDE_EXPLODED_DIRECTORY" value="true" />
+ <setting name="RUN_EJB_VALIDATION" value="true" />
+ </building>
+ <packaging>
+ <containerElement type="library" name="Seam" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/" />
+ </containerElement>
+ <containerElement type="library" name="api-other" level="application">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="<N/A>" />
+ </containerElement>
+ <containerElement type="library" name="hibernate" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/" />
+ </containerElement>
+ <containerElement type="library" name="javaee" level="application">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="<N/A>" />
+ </containerElement>
+ <containerElement type="library" name="rome" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/" />
+ </containerElement>
+ <containerElement type="library" name="search" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/" />
+ </containerElement>
+ <containerElement type="library" name="testng" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/" />
+ </containerElement>
+ <containerElement type="library" name="velocity" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/" />
+ </containerElement>
+ <containerElement type="library" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/" />
+ <url>jar://$MODULE_DIR$/lib/drools-core.jar!/</url>
+ </containerElement>
+ <containerElement type="library" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/" />
+ <url>jar://$MODULE_DIR$/lib/htmlcleaner1_6.jar!/</url>
+ </containerElement>
+ <containerElement type="library" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="<N/A>" />
+ <url>jar://$APPLICATION_HOME_DIR$/lib/javaee.jar!/</url>
+ </containerElement>
+ <containerElement type="library" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/" />
+ <url>jar://$MODULE_DIR$/lib/javassist.jar!/</url>
+ </containerElement>
+ <containerElement type="library" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/" />
+ <url>jar://$MODULE_DIR$/lib/jericho-html-2.5.jar!/</url>
+ </containerElement>
+ <containerElement type="library" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/" />
+ <url>jar://$MODULE_DIR$/lib/jsf-facelets.jar!/</url>
+ </containerElement>
+ <containerElement type="library" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/" />
+ <url>jar://$MODULE_DIR$/../jboss/lib/mysql.jar!/</url>
+ </containerElement>
+ <containerElement type="library" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/" />
+ <url>jar://$MODULE_DIR$/lib/portal-common-lib.jar!/</url>
+ </containerElement>
+ <containerElement type="library" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/" />
+ <url>jar://$MODULE_DIR$/lib/portal-identity-lib.jar!/</url>
+ </containerElement>
+ <containerElement type="library" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/" />
+ <url>jar://$MODULE_DIR$/lib/portal-portlet-jsr168api-lib.jar!/</url>
+ </containerElement>
+ <containerElement type="library" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/" />
+ <url>jar://$MODULE_DIR$/lib/shotoku-base.jar!/</url>
+ </containerElement>
+ <containerElement type="library" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/" />
+ <url>jar://$MODULE_DIR$/lib/urlrewritefilter.jar!/</url>
+ </containerElement>
+ </packaging>
+ </configuration>
+ </facet>
+ <facet type="web" name="Web">
+ <configuration>
+ <descriptors>
+ <deploymentDescriptor name="web.xml" url="file://$MODULE_DIR$/resources-portlet/WEB-INF/web.xml" optional="false" version="2.5" />
+ </descriptors>
+ <webroots>
+ <root url="file://$MODULE_DIR$/resources-portlet" relative="/" />
+ </webroots>
+ <building>
+ <setting name="EXPLODED_URL" value="file://" />
+ <setting name="EXPLODED_ENABLED" value="false" />
+ <setting name="JAR_URL" value="file://" />
+ <setting name="JAR_ENABLED" value="false" />
+ <setting name="BUILD_MODULE_ON_FRAME_DEACTIVATION" value="false" />
+ <setting name="BUILD_EXTERNAL_DEPENDENCIES" value="false" />
+ <setting name="EXCLUDE_EXPLODED_DIRECTORY" value="true" />
+ <setting name="RUN_JASPER_VALIDATION" value="true" />
+ <setting name="BUILD_ONLY_WEB_RESOURCES" value="false" />
+ </building>
+ <packaging>
+ <containerElement type="module" name="blog">
+ <attribute name="method" value="1" />
+ <attribute name="URI" value="/WEB-INF/classes" />
+ </containerElement>
+ <containerElement type="library" name="Seam" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/WEB-INF/lib" />
+ </containerElement>
+ <containerElement type="library" name="api-other" level="application">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="<N/A>" />
+ </containerElement>
+ <containerElement type="library" name="hibernate" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/WEB-INF/lib" />
+ </containerElement>
+ <containerElement type="library" name="javaee" level="application">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="<N/A>" />
+ </containerElement>
+ <containerElement type="library" name="rome" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/WEB-INF/lib" />
+ </containerElement>
+ <containerElement type="library" name="search" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/WEB-INF/lib" />
+ </containerElement>
+ <containerElement type="library" name="testng" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/WEB-INF/lib" />
+ </containerElement>
+ <containerElement type="library" name="velocity" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/WEB-INF/lib" />
+ </containerElement>
+ <containerElement type="library" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/WEB-INF/lib" />
+ <url>jar://$MODULE_DIR$/lib/drools-core.jar!/</url>
+ </containerElement>
+ <containerElement type="library" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/WEB-INF/lib" />
+ <url>jar://$MODULE_DIR$/lib/htmlcleaner1_6.jar!/</url>
+ </containerElement>
+ <containerElement type="library" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="<N/A>" />
+ <url>jar://$APPLICATION_HOME_DIR$/lib/javaee.jar!/</url>
+ </containerElement>
+ <containerElement type="library" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/WEB-INF/lib" />
+ <url>jar://$MODULE_DIR$/lib/javassist.jar!/</url>
+ </containerElement>
+ <containerElement type="library" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/WEB-INF/lib" />
+ <url>jar://$MODULE_DIR$/lib/jericho-html-2.5.jar!/</url>
+ </containerElement>
+ <containerElement type="library" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/WEB-INF/lib" />
+ <url>jar://$MODULE_DIR$/lib/jsf-facelets.jar!/</url>
+ </containerElement>
+ <containerElement type="library" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/WEB-INF/lib" />
+ <url>jar://$MODULE_DIR$/../jboss/lib/mysql.jar!/</url>
+ </containerElement>
+ <containerElement type="library" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/WEB-INF/lib" />
+ <url>jar://$MODULE_DIR$/lib/portal-common-lib.jar!/</url>
+ </containerElement>
+ <containerElement type="library" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/WEB-INF/lib" />
+ <url>jar://$MODULE_DIR$/lib/portal-identity-lib.jar!/</url>
+ </containerElement>
+ <containerElement type="library" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/WEB-INF/lib" />
+ <url>jar://$MODULE_DIR$/lib/portal-portlet-jsr168api-lib.jar!/</url>
+ </containerElement>
+ <containerElement type="library" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/WEB-INF/lib" />
+ <url>jar://$MODULE_DIR$/lib/shotoku-base.jar!/</url>
+ </containerElement>
+ <containerElement type="library" level="module">
+ <attribute name="method" value="0" />
+ <attribute name="URI" value="/WEB-INF/lib" />
+ <url>jar://$MODULE_DIR$/lib/urlrewritefilter.jar!/</url>
+ </containerElement>
+ </packaging>
+ </configuration>
+ <facet type="jsf" name="JSF" implicit="true">
+ <configuration />
+ </facet>
+ </facet>
+ </component>
+ <component name="NewModuleRootManager" inherit-compiler-output="true">
+ <exclude-output />
+ <content url="file://$MODULE_DIR$">
+ <sourceFolder url="file://$MODULE_DIR$/src/action" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/model" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/portal" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/services" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/shotoku" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/test" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/src/tools" isTestSource="false" />
+ <excludeFolder url="file://$MODULE_DIR$/dist" />
+ <excludeFolder url="file://$MODULE_DIR$/exploded-archives" />
+ </content>
+ <orderEntry type="inheritedJdk" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ <orderEntry type="library" name="api-other" level="application" />
+ <orderEntry type="library" name="javaee" level="application" />
+ <orderEntry type="module-library">
+ <library name="Seam">
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/lib/jboss-seam.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/jboss-seam-debug.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/jboss-seam-ui.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/jboss-seam-remoting.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/jboss-seam-pdf.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/jboss-seam-ioc.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/jboss-seam-mail.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/jboss-seam-gen.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library name="hibernate">
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/lib/hibernate-entitymanager.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/hibernate-commons-annotations.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/hibernate-annotations.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/hibernate-search.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/hibernate.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/hibernate-validator.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/commons-logging.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/commons-collections.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/commons-lang.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/commons-beanutils.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/cglib.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/commons-digester.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/asm.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/antlr.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/dom4j.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library name="rome">
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/lib/rome-0.9.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/jdom.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library>
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/lib/jsf-facelets.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library name="testng">
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/lib/testng.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/easymock.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library name="velocity">
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/lib/velocity-1.5.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/velocity-dep-1.5.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library>
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/lib/urlrewritefilter.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library name="search">
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/lib/lucene-core.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/hibernate-commons-annotations.jar!/" />
+ <root url="jar://$MODULE_DIR$/lib/hibernate-search.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES>
+ <root url="file://$MODULE_DIR$/../jboss/hibernate/search/src/java" />
+ </SOURCES>
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library>
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/lib/jericho-html-2.5.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library>
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/lib/javassist.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library>
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/lib/htmlcleaner1_6.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library>
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/../jboss/lib/mysql.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library>
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/lib/drools-core.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library>
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/lib/portal-portlet-jsr168api-lib.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library>
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/lib/shotoku-base.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library>
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/lib/portal-identity-lib.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library>
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/lib/portal-common-lib.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library>
+ <CLASSES>
+ <root url="jar://$APPLICATION_HOME_DIR$/lib/javaee.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library>
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/../.maven/repository/jboss/jars/jgroups.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library>
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/../.maven/repository/jboss/jars/jboss-cache.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library>
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/../.maven/repository/jboss/jars/jboss-system.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library>
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/../.maven/repository/jboss/jars/jboss-jmx.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library>
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/lib/let-tag.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ <orderEntryProperties />
+ </component>
+</module>
+
Added: feeds100P26/build-design.properties
===================================================================
--- feeds100P26/build-design.properties (rev 0)
+++ feeds100P26/build-design.properties 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1 @@
+debug=true
Added: feeds100P26/build-dev.properties
===================================================================
--- feeds100P26/build-dev.properties (rev 0)
+++ feeds100P26/build-dev.properties 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,2 @@
+debug=true
+action.dir=WEB-INF/dev
Added: feeds100P26/build-prod.properties
===================================================================
--- feeds100P26/build-prod.properties (rev 0)
+++ feeds100P26/build-prod.properties 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,4 @@
+debug=false
+
+
+
Added: feeds100P26/build.properties
===================================================================
--- feeds100P26/build.properties (rev 0)
+++ feeds100P26/build.properties 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,6 @@
+#jboss.home = /Users/adamwarski/portal-extensions/feeds/binaries
+jboss.home = /Users/adamwarski/jboss/jboss-4.2
+#jboss.home = /Users/adamwarski/jboss/jboss-4.0.5
+profile = dev
+#profile = prod
+#jboss.home = /Users/adamwarski/jboss/jboss-design
\ No newline at end of file
Added: feeds100P26/build.xml
===================================================================
--- feeds100P26/build.xml (rev 0)
+++ feeds100P26/build.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,477 @@
+<?xml version="1.0"?>
+
+<project name="blog" default="deploy" basedir=".">
+ <!-- Give user a chance to override without editing this file or typing -D -->
+ <property file="${basedir}/build.properties" />
+
+ <property name="profile" value="dev" />
+ <property file="${basedir}/build-${profile}.properties" />
+
+ <!-- set global properties for this build -->
+ <property name="project.name" value="blog"/>
+ <property name="dist.dir" value="dist" />
+ <property name="src.model.dir" value="src/model" />
+ <property name="src.action.dir" value="src/action" />
+ <property name="src.services.dir" value="src/services" />
+ <property name="src.tools.dir" value="src/tools" />
+ <property name="src.test.dir" value="src/test" />
+ <property name="src.portal.dir" value="src/portal" />
+ <property name="src.shotoku.dir" value="src/shotoku" />
+ <property name="lib.dir" value="lib" />
+
+ <property name="jar.impl.name" value="${project.name}-impl.jar" />
+ <property name="jar.api.name" value="${project.name}.jar" />
+ <property name="jar.shotoku.name" value="${project.name}-shotoku.jar" />
+ <property name="jar.portal.name" value="${project.name}-portal.jar" />
+ <property name="portal.name" value="${project.name}-portal.war" />
+
+ <property name="ear.dir" value="exploded-archives/${project.name}.ear" />
+ <property name="jar.impl.dir" value="exploded-archives/${jar.impl.name}" />
+ <property name="jar.api.dir" value="exploded-archives/${jar.api.name}" />
+ <property name="jar.shotoku.dir" value="exploded-archives/${jar.shotoku.name}" />
+ <property name="jar.portal.dir" value="exploded-archives/${jar.portal.name}" />
+ <property name="war.dir" value="exploded-archives/${project.name}.war" />
+ <property name="portal.dir" value="exploded-archives/${portal.name}" />
+ <property name="test.dir" value="test-build" />
+ <property name="bootstrap.dir" value="${basedir}/bootstrap" />
+ <property name="deploy.dir" value="${jboss.home}/server/default/deploy" />
+ <property name="deploy.lib.dir" value="${jboss.home}/server/default/lib" />
+ <property name="ear.deploy.dir" value="${deploy.dir}/${project.name}.ear" />
+ <property name="jar.deploy.dir" value="${ear.deploy.dir}/${jar.impl.name}" />
+ <property name="jar.shotoku.deploy.dir" value="${ear.deploy.dir}/${jar.shotoku.name}" />
+ <property name="jar.portal.deploy.dir" value="${ear.deploy.dir}/${jar.portal.name}" />
+ <property name="war.deploy.dir" value="${ear.deploy.dir}/${project.name}.war" />
+ <property name="portal.deploy.dir" value="${ear.deploy.dir}/${portal.name}" />
+ <property name="testng.jar" value="${basedir}/lib/testng.jar" />
+ <property name="javac.debug" value="true" />
+ <property name="javac.deprecation" value="false" />
+ <property name="debug" value="false" />
+
+ <!--Properties for validating configuration files -->
+ <property name="validate.resources.dir" value="${basedir}/exploded-archives" />
+ <property name="schema.dir" value="${basedir}/exploded-archives/schemas" />
+ <property name="src.schema.dir" value="${schema.dir}/org/jboss/seam"/>
+ <property name="schema.version" value="2.0" />
+
+ <fileset id="lib" dir="${lib.dir}">
+ <include name="*.jar" />
+ </fileset>
+
+ <path id="build.api.classpath">
+ <fileset refid="lib" />
+ </path>
+
+ <path id="build.impl.classpath">
+ <fileset refid="lib" />
+ <pathelement path="${jar.api.dir}" />
+ </path>
+
+ <path id="build.dep.classpath">
+ <fileset refid="lib" />
+ <pathelement path="${jar.api.dir}" />
+ <pathelement path="${jar.impl.dir}" />
+ </path>
+
+ <target name="init" description="Initialize the build">
+ <mkdir dir="${jar.impl.dir}" />
+ <mkdir dir="${jar.api.dir}" />
+ <mkdir dir="${jar.shotoku.dir}" />
+ <mkdir dir="${jar.portal.dir}" />
+ <mkdir dir="${ear.dir}" />
+ <mkdir dir="${war.dir}" />
+ <mkdir dir="${portal.dir}" />
+ <mkdir dir="${portal.dir}/WEB-INF" />
+ <mkdir dir="${portal.dir}/WEB-INF/lib" />
+ <mkdir dir="${dist.dir}" />
+ </target>
+
+ <target name="compile" depends="init"
+ description="Compile the Java source code">
+ <javac classpathref="build.api.classpath"
+ destdir="${jar.api.dir}"
+ debug="${javac.debug}"
+ deprecation="${javac.deprecation}"
+ nowarn="on">
+ <src path="${src.tools.dir}" />
+ <src path="${src.services.dir}" />
+ <src path="${src.model.dir}" />
+ </javac>
+ <javac classpathref="build.impl.classpath"
+ destdir="${jar.impl.dir}"
+ debug="${javac.debug}"
+ deprecation="${javac.deprecation}"
+ nowarn="on">
+ <src path="${src.action.dir}" />
+ </javac>
+ <javac classpathref="build.dep.classpath"
+ destdir="${jar.portal.dir}"
+ debug="${javac.debug}"
+ deprecation="${javac.deprecation}"
+ nowarn="on">
+ <src path="${src.portal.dir}" />
+ </javac>
+ <javac classpathref="build.dep.classpath"
+ destdir="${jar.shotoku.dir}"
+ debug="${javac.debug}"
+ deprecation="${javac.deprecation}"
+ nowarn="on">
+ <src path="${src.shotoku.dir}" />
+ </javac>
+ </target>
+
+ <target name="jar" depends="compile"
+ description="Build the distribution .jar file">
+ <!-- Jars for model and services -->
+ <jar jarfile="${dist.dir}/${jar.api.name}" basedir="${jar.api.dir}"/>
+
+ <!-- Jar for action -->
+ <copy todir="${jar.impl.dir}">
+ <fileset dir="${basedir}/resources">
+ <include name="seam.properties" />
+ </fileset>
+ </copy>
+
+ <!-- TODO: remove this marker for scanner -->
+ <copy todir="${jar.shotoku.dir}">
+ <fileset dir="${basedir}/resources">
+ <include name="seam.properties" />
+ </fileset>
+ </copy>
+
+ <!-- TODO: remove this marker for scanner -->
+ <copy todir="${jar.portal.dir}">
+ <fileset dir="${basedir}/resources">
+ <include name="seam.properties" />
+ </fileset>
+ </copy>
+
+ <copy todir="${jar.impl.dir}/META-INF">
+ <fileset dir="${basedir}/resources/META-INF">
+ <include name="ejb-jar.xml" />
+ </fileset>
+ </copy>
+ <copy tofile="${jar.impl.dir}/META-INF/persistence.xml"
+ file="${basedir}/resources/META-INF/persistence-${profile}.xml"
+ overwrite="true"/>
+
+ <!-- Shotoku -->
+ <jar jarfile="${dist.dir}/${jar.shotoku.name}" basedir="${jar.shotoku.dir}"/>
+ </target>
+
+ <target name="war" depends="compile"
+ description="Build the distribution .war file">
+ <copy todir="${war.dir}">
+ <fileset dir="${basedir}/view" />
+ </copy>
+ <copy todir="${war.dir}">
+ <fileset dir="${basedir}/resources">
+ <include name="templates/**/*.*" />
+ </fileset>
+ </copy>
+ <copy todir="${war.dir}/WEB-INF">
+ <fileset dir="${basedir}/resources/WEB-INF">
+ <include name="*.*"/>
+ <include name="classes/**/*.*"/>
+ <exclude name="classes/**/*.class"/>
+ <exclude name="web-*.xml" />
+ </fileset>
+ <filterset>
+ <filter token="debug" value="${debug}" />
+ <filter token="jndiPattern" value="${project.name}/#{ejbName}/local" />
+ <filter token="embeddedEjb" value="false" />
+ </filterset>
+ </copy>
+ <copy tofile="${war.dir}/WEB-INF/web.xml" file="${basedir}/resources/WEB-INF/web-${profile}.xml">
+ <filterset>
+ <filter token="debug" value="${debug}" />
+ <filter token="jndiPattern" value="${project.name}/#{ejbName}/local" />
+ <filter token="embeddedEjb" value="false" />
+ </filterset>
+ </copy>
+ <copy todir="${war.dir}/WEB-INF">
+ <fileset dir="${basedir}/resources/WEB-INF">
+ <include name="lib/*.*"/>
+ <include name="classes/**/*.class"/>
+ </fileset>
+ </copy>
+ <!--<copy todir="${war.dir}/WEB-INF/lib">
+ <fileset dir="${lib.dir}">
+ moved to ear goal
+ </fileset>
+ </copy> -->
+ <copy todir="${war.dir}/WEB-INF/classes">
+ <fileset dir="${basedir}/resources">
+ <include name="messages*.properties"/>
+ </fileset>
+ </copy>
+
+ <copy todir="${portal.dir}">
+ <fileset dir="${basedir}/resources-portlet">
+ <include name="**/*"/>
+ </fileset>
+ </copy>
+ <copy todir="${portal.dir}">
+ <fileset dir="${basedir}/view-portlet">
+ <include name="**/*"/>
+ </fileset>
+ </copy>
+ <copy todir="${portal.dir}/WEB-INF/lib">
+ <fileset dir="${basedir}/lib">
+ <include name="jstl.jar" />
+ <include name="standard.jar" />
+ </fileset>
+ </copy>
+ </target>
+
+ <target name="ear" description="Build the EAR">
+ <copy todir="${ear.dir}">
+ <fileset dir="${basedir}/resources">
+ <include name="*jpdl.xml" />
+ <include name="hibernate.cfg.xml" />
+ <include name="jbpm.cfg.xml" />
+ <include name="*.drl" />
+ <include name="velocity.properties"/>
+ <include name="treecache.xml" />
+ <include name="blog-ehcache.xml" />
+ </fileset>
+ <fileset dir="${lib.dir}">
+ <include name="jboss-seam.jar" />
+ </fileset>
+ <fileset dir="${basedir}">
+ <include name="lib/jbpm*.jar" />
+ <include name="lib/jboss-el.jar" />
+ <include name="lib/drools-*.jar"/>
+ <include name="lib/janino-*.jar"/>
+ <include name="lib/antlr-*.jar"/>
+ <include name="lib/mvel*.jar"/>
+ <include name="lib/richfaces-api*.jar" />
+ <include name="lib/rome*.jar" />
+
+ <include name="lib/jgroups*.jar" />
+ <include name="lib/jboss-cache*.jar" />
+
+ <!--<include name="lib/ehcache*.jar" />-->
+
+ <!-- Moved to server/default/lib
+ <include name="lib/hibernate*.jar" />
+
+ <include name="lib/lucene-core.jar" />
+ <include name="lib/hibernate-search.jar" />
+ <include name="lib/hibernate-commons-annotations.jar" />-->
+
+ <!-- moved from the war goal -->
+ <include name="lib/richfaces-impl*.jar" />
+ <include name="lib/richfaces-ui*.jar" />
+ <include name="lib/oscache*.jar" />
+ <include name="lib/commons-digester.jar" />
+ <include name="lib/commons-beanutils.jar" />
+ <include name="lib/jsf-facelets.jar" />
+ <include name="lib/velocity*.jar" />
+ <include name="lib/urlrewritefilter.jar" />
+ <include name="lib/jboss-seam-*.jar" />
+ <exclude name="lib/jboss-seam-gen.jar" />
+
+ <include name="lib/let-tag.jar" />
+
+ <!-- Luca Stancapiano - added to use jbossblog as portlet -->
+ <include name="lib/shotoku-base.jar" />
+ <include name="lib/commons-configuration-1.6.jar" /> <!-- not included -->
+ <include name="lib/commons-lang-2.4.jar" /> <!-- not included -->
+ <!--<include name="lib/ehcache*.jar" />
+ <include name="lib/jdom*.jar" />
+ <include name="lib/jericho-html-*.jar" />
+ <include name="lib/htmlcleaner*.jar" /> -->
+
+ <!--<include name="lib/hibernate3.jar" />
+ <include name="lib/hibernate-annotations.jar" />
+ <include name="lib/hibernate-entitymanager.jar" />
+ <include name="lib/hibernate-commons-annotations.jar" />
+ <include name="lib/hibernate.jar" />
+ <include name="lib/hibernate-search.jar" />
+ <include name="lib/hibernate-validator.jar" /> -->
+
+ <!-- <include name="lib/lucene*.jar" /> -->
+ <!-- end -->
+ </fileset>
+ </copy>
+ <copy todir="${ear.dir}/META-INF">
+ <fileset dir="${basedir}/resources/META-INF">
+ <include name="application.xml" />
+ <include name="jboss-app.xml" />
+ <include name="jbossblog.taglib.xml" />
+ <include name="security.drl" />
+ </fileset>
+ </copy>
+ </target>
+
+ <target name="archive" depends="jar,war,ear"
+ description="Package the archives">
+ <jar jarfile="${dist.dir}/${jar.impl.name}" basedir="${jar.impl.dir}"/>
+ <jar jarfile="${dist.dir}/${jar.shotoku.name}" basedir="${jar.shotoku.dir}"/>
+ <jar jarfile="${dist.dir}/${jar.portal.name}" basedir="${jar.portal.dir}"/>
+ <jar jarfile="${dist.dir}/${project.name}.war" basedir="${war.dir}"/>
+ <jar jarfile="${dist.dir}/${portal.name}" basedir="${portal.dir}"/>
+ <jar jarfile="${dist.dir}/${project.name}.ear">
+ <fileset dir="${ear.dir}"/>
+ <fileset dir="${dist.dir}">
+ <include name="${jar.impl.name}"/>
+ <include name="${jar.shotoku.name}"/>
+ <include name="${jar.portal.name}"/>
+ <include name="${project.name}.war"/>
+ <include name="${portal.name}"/>
+ </fileset>
+ </jar>
+ </target>
+
+ <target name="datasource">
+ <fail unless="jboss.home">jboss.home not set</fail>
+ <copy todir="${deploy.dir}">
+ <fileset dir="${basedir}/resources">
+ <include name="${project.name}-${profile}-ds.xml" />
+ </fileset>
+ </copy>
+ </target>
+
+ <target name="prepare-as-lib">
+ <copy todir="${deploy.lib.dir}" overwrite="true">
+ <fileset dir="${basedir}/lib">
+ <include name="ehcache*.jar" />
+ <include name="jdom*.jar" />
+ <include name="jericho-html-*.jar" />
+ <include name="htmlcleaner*.jar" />
+ <include name="hibernate*.jar" />
+ <include name="lucene*.jar" />
+ </fileset>
+ </copy>
+ </target>
+
+ <target name="explode" depends="jar,war,ear"
+ description="Deploy the exploded archive">
+ <fail unless="jboss.home">jboss.home not set</fail>
+
+ <mkdir dir="${jar.deploy.dir}"/>
+ <mkdir dir="${war.deploy.dir}"/>
+ <mkdir dir="${portal.deploy.dir}"/>
+
+ <copy todir="${jar.deploy.dir}">
+ <fileset dir="${jar.impl.dir}"/>
+ </copy>
+ <copy todir="${jar.shotoku.deploy.dir}">
+ <fileset dir="${jar.shotoku.dir}"/>
+ </copy>
+ <copy todir="${jar.portal.deploy.dir}">
+ <fileset dir="${jar.portal.dir}"/>
+ </copy>
+ <copy todir="${war.deploy.dir}">
+ <fileset dir="${war.dir}"/>
+ </copy>
+ <copy todir="${portal.deploy.dir}">
+ <fileset dir="${portal.dir}"/>
+ </copy>
+ <copy todir="${ear.deploy.dir}">
+ <fileset dir="${ear.dir}"/>
+ </copy>
+
+ <copy todir="${deploy.dir}">
+ <fileset dir="${dist.dir}">
+ <include name="${jar.api.name}" />
+ </fileset>
+ </copy>
+
+ <!--<copy todir="${deploy.dir}" file="${basedir}/resources/blog-ehcache.xml" />-->
+
+ <ant target="prepare-as-lib" />
+ </target>
+
+ <target name="unexplode" description="Undeploy the exploded archive">
+ <delete failonerror="no">
+ <fileset dir="${ear.deploy.dir}">
+ <exclude name="**/*.jar"/>
+ </fileset>
+ </delete>
+ <delete dir="${ear.deploy.dir}" failonerror="no"/>
+
+ <delete file="${deploy.dir}/${jar.api.name}" />
+ </target>
+
+ <target name="restart" depends="clean,unexplode,explode" description="Restart the exploded archive">
+ <touch file="${ear.deploy.dir}/META-INF/application.xml"/>
+ </target>
+
+ <target name="deploy" depends="clean,archive" description="Deploy to JBoss AS">
+ <fail unless="jboss.home">jboss.home not set</fail>
+ <copy todir="${deploy.dir}" file="${dist.dir}/${project.name}.ear" />
+ <copy todir="${deploy.dir}" file="${dist.dir}/${jar.api.name}" />
+ <ant target="prepare-as-lib" />
+ </target>
+
+ <target name="undeploy" description="Undeploy the example from JBoss">
+ <delete file="${deploy.dir}/${project.name}.ear" />
+ <delete file="${deploy.dir}/${jar.api.name}" />
+ </target>
+
+ <target name="clean" description="Cleans up the build directory">
+ <delete dir="${dist.dir}"/>
+ <delete dir="${ear.dir}"/>
+ <delete dir="${war.dir}"/>
+ <delete dir="${portal.dir}"/>
+ <delete dir="${jar.impl.dir}"/>
+ <delete dir="${jar.api.dir}"/>
+ <delete dir="${jar.portal.dir}"/>
+ <delete dir="${src.schema.dir}" failonerror="no"/>
+ <delete dir="${basedir}/test-report"/>
+ <delete dir="${basedir}/test-output"/>
+ </target>
+
+ <target name="clean-all" depends="undeploy,unexplode,clean" />
+
+ <target name="compiletest" unless="eclipse.running" description="Compile the Java source code for the tests">
+ <mkdir dir="${test.dir}"/>
+ <javac classpathref="build.impl.classpath"
+ destdir="${test.dir}"
+ debug="${javac.debug}"
+ deprecation="${javac.deprecation}"
+ nowarn="on">
+ <src path="${src.action.dir}" />
+ <src path="${src.model.dir}" />
+ <src path="${src.test.dir}" />
+ </javac>
+ </target>
+
+ <target name="buildtest" depends="compiletest" description="Build the tests">
+ <copy todir="${test.dir}">
+ <fileset dir="${basedir}/resources">
+ <exclude name="META-INF/persistence*.xml"/>
+ <exclude name="import*.sql"/>
+ <exclude name="${project.name}-*-ds.xml"/>
+ </fileset>
+ </copy>
+ <copy tofile="${test.dir}/META-INF/persistence.xml"
+ file="${basedir}/resources/META-INF/persistence-test.xml"
+ overwrite="true"/>
+ <copy tofile="${test.dir}/import.sql"
+ file="${basedir}/resources/import-test.sql"
+ overwrite="true"/>
+ <copy todir="${test.dir}" flatten="true">
+ <fileset dir="${src.test.dir}">
+ <include name="**/*Test.xml" />
+ </fileset>
+ </copy>
+ </target>
+
+ <target name="test" depends="buildtest" description="Run the tests">
+ <taskdef resource="testngtasks" classpath="${testng.jar}" />
+ <path id="test.path">
+ <path path="${test.dir}" />
+ <fileset dir="${lib.dir}/test">
+ <include name="*.jar"/>
+ </fileset>
+ <path path="${bootstrap.dir}" />
+ <path refid="build.impl.classpath" />
+ </path>
+ <testng outputdir="${basedir}/test-report">
+ <classpath refid="test.path" />
+ <xmlfileset dir="${test.dir}" includes="*Test.xml" />
+ </testng>
+ </target>
+</project>
Added: feeds100P26/docs/admin_link.png
===================================================================
(Binary files differ)
Property changes on: feeds100P26/docs/admin_link.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/docs/group_header.png
===================================================================
(Binary files differ)
Property changes on: feeds100P26/docs/group_header.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/docs/tutorial.html
===================================================================
--- feeds100P26/docs/tutorial.html (rev 0)
+++ feeds100P26/docs/tutorial.html 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,371 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>JBoss.ORG Feeds tutorial</title>
+ <link rel="stylesheet" href="http://www.jboss.org/files/portletcontainer/docs/2.0.0.CR1/css/jbossorg.css" type="text/css"/>
+</head>
+<body>
+<p id="title">
+ <a href="http://www.jboss.org" class="jbossOrg_href">
+ <strong>
+ JBoss.org
+ </strong>
+ </a>
+ <a href="http://labs.jboss.com/projects/docs" class="commDoc_href">
+ <strong>
+ Community Documentation
+ </strong>
+ </a>
+</p>
+<div class="book" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+
+ <h1 class="title">
+ <a id="d0e1"/>JBoss.ORG Feeds</h1>
+ </div>
+ <div>
+ <h2 class="subtitle">Tutorial</h2>
+ </div>
+ <div>
+ <div class="author">
+
+ <h3 class="author">
+ <span class="firstname">Adam</span>
+ <span class="surname">Warski</span>
+ </h3>
+ <code class="email"><<a href="mailto:adam.warski at jboss.org">adam.warski at jboss.org</a>></code>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+
+<div class="sect1">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title">1. About</h2>
+ </div>
+ </div>
+ </div>
+ <p>The Feeds application has two main functions:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li><span class="bold"><strong>aggregating</strong></span> blogs of JBoss employees</li>
+ <li><span class="bold"><strong>archiving</strong></span> posts</li>
+ </ul>
+ </div>
+ <p>It is not meant to be a blog-authoring application. So you should have an outside blog (on Blogger,
+ Wordpress or wherever), which you use for authoring, and then aggregate it into the feeds system.</p>
+
+ <p>If you have any questions about the application, please mail me. If you see a bug, mail me or create
+ a bug in <a href="http://jira.jboss.com/jira/browse/JBBLOG">JIRA</a>. The same applies for feature suggestions,
+ improvements, .... Thanks :).</p>
+
+ <p>Also, when using the application, you'll probably notice a "Tips" box on the right - it often contains
+ description of configuration parameters, explains the meaning of some options etc.</p>
+</div>
+
+<div class="sect1">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title">2. Groups, feeds, posts</h2>
+ </div>
+ </div>
+ </div>
+ <p>The application is organized around <span class="bold"><strong>feeds</strong></span>. A feed is linked to an
+ arbitrary number of <span class="bold"><strong>posts</strong></span>. However, the fact that a feed is linked to
+ a post doesn't imply that it is the owner of that post. A feed owns a post if that post originated from that feed;
+ for some types of feeds, there are no posts which originate from them, see below.</p>
+
+ <p>Feeds are organized in <span class="bold"><strong>groups</strong></span>. Basically, one project should have
+ one group, and all feeds that belong to that project should be in that group. For example, all feeds of blogs
+ of people involved in a project should belong to that project's feed group.</p>
+
+ <p>Each post, feed and group have a unique id, which is a sequence of lowercase letters, numbers and _. The
+ id for a post is determined basing on its title, and the ids for feeds and groups are determined by their
+ creators.</p>
+</div>
+
+<div class="sect1">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title">3. Types of feeds</h2>
+ </div>
+ </div>
+ </div>
+ <p>There are currently 5 types of feeds. The "type" of a feed is invisible to the user. It just determines the
+ way that posts of a feed are determined. The types are:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li><span class="bold"><strong>remote feed</strong></span> - a feed which reads and archives posts
+ from an XML feed, given as an internet address. The XML feed can be of any type (RSS2/ATOM/RDF).
+ All posts that are linked to this feed are also owned
+ by this feed, so if you delete a remote feed, you also delete all posts that where archived.</li>
+ <li><span class="bold"><strong>aggregated feed</strong></span> - a feed which combines posts from other
+ feeds, or groups. For example, you may want to create an aggregated feed for all blog feeds of your
+ project. For simplicity, you may simply aggregate posts from feeds that belong to your group,
+ by aggregating that group. You may include posts from any number of feeds/ groups. Moreover, you
+ can filter which posts from a feed/ group you want, by adding post filters. Such filters may accept only
+ posts by a specific author, or from a specific category. This type of feed doesn't own the posts that
+ are linked to it.</li>
+ <li><span class="bold"><strong>shotoku feed</strong></span> - a feed which reads posts
+ from a directory in SVN. The posts are files in that directory; post titles are the svn 'title' property
+ on that files. This feed also owns all posts that are linked to it.</li>
+ <li><span class="bold"><strong>highlights feed</strong></span> - a feed which lets you choose posts
+ that will appear in it, and their order. This can be very useful if you'd like to have on your webpage
+ a "top news" or "top blog posts of the month" window. Of course, this feed doesn't own the posts that
+ are linked to it.</li>
+ <li><span class="bold"><strong>individual posts feed</strong></span> - a feed which lets you include
+ posts from arbitrary remote feeds individually - that is, without including the whole feed in the
+ system. This may be useful if you want to promote some community posts, for example.</li>
+ </ul>
+ </div>
+</div>
+
+<div class="sect1">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title">4. Archiving</h2>
+ </div>
+ </div>
+ </div>
+ <p>All feeds are updated in regular intervals of time (by default, every 15 minutes). In case of a remote feed
+ it means that if there are new posts, they will get merged with the posts that are currently held in the database.
+ No posts are deleted during merging, so if a post disappears from a remote feed (because, for example, the
+ remote feed has only 10 newest posts), it won't disappear from the feeds system.</p>
+
+ <p>This has one drawback, though: if you are not entirely concious when you get home in the evening, and decide to
+ write a very sincere post, with a degree of sincerity which isn't normally viewed as good manners, and in the
+ morning realize that you should delete the post, you'll have to delete it from the feeds sytem manually.</p>
+
+ <p>If you change your post, for example alter the content, the change will be picked up and the post in the
+ database will also be updated. With one exception: when you change the published date. That will be seen as a new
+ post.</p>
+</div>
+
+<div class="sect1">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title">5. Viewing</h2>
+ </div>
+ </div>
+ </div>
+ <p>Users can view the feeds and posts using the webpage, or using an ATOM feed. When viewing a post (either
+ as part of a feed page, or as part of a post page), there is always a link back to the original post, so that
+ users can, for example, add comments. The URL schemes are:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li><code>http://labs.jboss.com/feeds/view/FEED_ID?from=X</code> - for viewing a feed with id
+ <code>FEED_ID</code>, starting from post number <code>X</code>.</li>
+ <li><code>http://labs.jboss.com/feeds/xml/FEED_ID?type=atom</code> - for getting an ATOM feed of a feed
+ with id <code>FEED_ID</code>.</li>
+ <li><code>http://labs.jboss.com/feeds/post/POST_ID</code> - for viewing a single post, with id
+ <code>POST_ID</code>.</li>
+ </ul>
+ </div>
+ <p>Because all posts are archived, the URLs for posts will be valid even after the posts disappear from a blog
+ feed (normally blog feeds contain only the 10 or so newest posts). Also, the page for viewing a single post contains
+ a link to the owning feed of that post.</p>
+
+ <p>How many posts appear on each page when viewing a feed, and how many posts appear in the ATOM feed, depends
+ on feed settings. See the section on administration for information on how to set these and other properties.</p>
+
+ <p>You can also customize the right part of the "View feed" page a little. For example, you may want to include
+ a "Back to MyProject page" link and a logo. You can do that, by setting a "Group header". It is a piece of HTML,
+ which will be displayed right below the "Feeds home" link, when viewing any feed or post belonging to that group.
+ To set it, got to manage home -> manage groups -> edit group.</p>
+
+ <p>Here is an example:</p>
+
+ <p><img src="group_header.png" alt="" /></p>
+
+ <p>And the corresponding HTML:</p>
+
+ <code>
+<a href="/jbossjbpm"><br />
+<img width="200" src="/file-access/default/members/jbossjbpm/images/jbpm_logo.png" alt="" /><br />
+</a><br />
+<br />
+<ul><br />
+ <li><a href="/jbossjbpm">Back to the JBoss jBPM project page</a></li><br />
+</ul>
+ </code>
+</div>
+
+<div class="sect1">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title">6. Community involvement</h2>
+ </div>
+ </div>
+ </div>
+ <p>Normal users (which aren't JBoss employees) have the possibility to
+ <span class="bold"><strong>propose</strong></span> their feeds for inclusion in the system. Of course, the
+ posts have to be JBoss- or JBoss project X- related. Users can only add remote feeds, and before they get
+ included in the system, they have to be accepted by a group administrator (when proposing a blog, users state to
+ which group they think it should belong). You may also create separate groups
+ for community and employee blogs.</p>
+
+ <p>To receive notifications about new proposed feeds in your group, you have to set the "Administrator e-mail"
+ field in group administration (see the "Administration" section, page: Manage feeds -> Manage feed groups ->
+ Group X edit).</p>
+
+ <p>To accept or reject proposed feeds, go to manage home -> pending feed propositions. There you'll see a table
+ presenting the proposed feeds, with the feed address (so that you can actually look at the posts) and a
+ regular expression determining posts from which categories will be included. When you click "Accept", you'll have
+ the possibility to change the properties of the feed, as well as see which posts will be saved.</p>
+</div>
+
+<div class="sect1">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title">7. Permissions</h2>
+ </div>
+ </div>
+ </div>
+ <p>You can have the following administrative permissions:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li><span class="bold"><strong>group X manager</strong></span> - having this role, you can edit
+ the name, id, header of the given group. You can also add new feeds, and edit properties of existing ones.
+ Moreover, you're able to create new feed groups. Finally, you can administrate security for that group -
+ that is, grant other users/user groups the permission to be a group or feed manager</li>
+ <li><span class="bold"><strong>feed X manager</strong></span> - having this role, you can edit
+ the properties of the given feed</li>
+ <li><span class="bold"><strong>view feed X</strong></span> - having this role, you view a given
+ restricted feed</li>
+ </ul>
+ </div>
+</div>
+
+<div class="sect1">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title">8. Administration</h2>
+ </div>
+ </div>
+ </div>
+ <p>To access the administration of feeds, simply login using your jboss.com login and password. If you are
+ authorized to manage anything, you should see additional links like this, near the top, on the right:</p>
+
+ <p><img src="admin_link.png" alt=""/></p>
+
+ <p>If you don't see it, then you don't have any administrative rights. Mail your manager or me if you think
+ you should have them. Basically, if you are a manager of a project in Labs (that is, after loggin in to
+ labs.jboss.com you can see the "Edit project" button), you should be a manager of a corresponding group
+ in feeds.</p>
+
+ <p>After clicking that link, you'll see the following options:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li><span class="bold"><strong>Manage feed groups</strong></span> - lets you edit and add feed groups
+ (for example, group headers)</li>
+ <li><span class="bold"><strong>Manage security</strong></span> - lets you configure permissions for
+ accessing feeds and groups that you have permissions to</li>
+ <li>for each feed: <span class="bold"><strong>Edit common</strong></span> - lets you edit "common"
+ properties of a feed, that is, properties that all feed types share, like the number of posts in
+ a feed, number of posts displayed on a "View feed" page, title and author of the feed, etc.</li>
+ <li>for each feed: <span class="bold"><strong>Edit specific</strong></span> - lets you edit "specifc"
+ properties of a feed, that is, properties unique to that type of feed. That is, for a remote feed -
+ the address of the XML, for an aggregated feed - what is aggregated and with what filters, for a
+ highlights feed - the order of posts, for a shotoku feed - the directory, from which posts are read.</li>
+ </ul>
+ </div>
+
+ <p>To add posts to a highlights feed, simply create the feed (if it's not yet created), navigate to the post
+ that you want to add and click the "Add to a highlights feed ..." link that should appear there.</p>
+</div>
+
+<div class="sect1">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title">9. Feeds portlet</h2>
+ </div>
+ </div>
+ </div>
+ <p>You can place one or more feeds portlets on your project page. To do that, log into Labs
+ (http://labs.jboss.com), navigate to your project and click the "Edit project" button. There
+ go to "Portlet selection". Choose the portal page on which you want the portlet placed, and
+ then from the left combo box choose "blog". Click the right arrow and the portlet is then
+ added to the selected page. Finally, specify its properties:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li><span class="bold"><strong>feedName</strong></span> - id of the feed that you want to display; this is
+ the id that you input when editing feed properties, and that is also visible in URLs when viewing this
+ feed</li>
+ <li><span class="bold"><strong>numberOfPosts</strong></span> - how many headers of posts you want to display
+ </li>
+ <li><span class="bold"><strong>summaryLength</strong></span> - if a summary of post content should be shown
+ below the post headings, this should be the number of characters you'd like it to contain (200 is a sensible
+ default). If you don't want to have a summary displayed, set it to 0</li>
+ <li><span class="bold"><strong>showDate</strong></span> - should the date of publishing the post be
+ displayed below the header</li>
+ </ul>
+ </div>
+
+ <p>The portlet always renders a number of post titles, which link to "View post" pages, optionally with a summary
+ of the post content and the publishing date of the post. At the bottom, you'll also see two links: one to the
+ "View feed" page of the selected feed, other to the home feeds page.</p>
+</div>
+
+<div class="sect1">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title">10. Restricted feeds</h2>
+ </div>
+ </div>
+ </div>
+ <p>If you mark a feed as <strong>restricted</strong>, it will be viewable only by persons, who are authorized to
+ view it, that is:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li>administrators of that feed</li>
+ <li>administrators of the group, to which the feed belongs</li>
+ <li>users who are granted the "view feed" role (you can set this in the security manager)</li>
+ </ul>
+ </div>
+ <p>To view a restricted feed with the browser, you'll need to log in. However, to view the ATOM xml feed, you
+ don't need to login - you just need to know the key (that makes restricted feeds more feed-reader friendly).
+ A key will be automatically generated for you, and you don't really need to manipulate it - when you'll be viewing
+ a restricted feed using the browser, the link to the ATOM xml feed will already contain the key. If, for any reason,
+ you'd like to change the key (if it was compromised, for example), simply login, click "User account" and
+ "Re-generate the security key".</p>
+</div>
+
+<div class="sect1">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title">11. Future improvements</h2>
+ </div>
+ </div>
+ </div>
+ <p>Here's some features planned for the future:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li>statistics</li>
+ <li>users proposing a single post, not a whole feed</li>
+ <li>del.icio.us integration</li>
+ <li>adding more structure to authors (binding authors to users, searching for posts by a specific
+ author/user)</li>
+ <li>anything you suggest -> <a href="mailto:adam.warski at jboss.org">adam.warski at jboss.org</a></li>
+ </ul>
+ </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
Added: feeds100P26/lib/activation.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/activation.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/ant-antlr.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/ant-antlr.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/antlr-runtime.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/antlr-runtime.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/antlr.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/antlr.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/asm-attrs.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/asm-attrs.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/asm.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/asm.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/cglib-nodep.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/cglib-nodep.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/cglib.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/cglib.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/commons-beanutils.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/commons-beanutils.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/commons-collections.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/commons-collections.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/commons-configuration-1.6.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/commons-configuration-1.6.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/commons-digester.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/commons-digester.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/commons-lang-2.4.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/commons-lang-2.4.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/commons-lang.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/commons-lang.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/commons-logging.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/commons-logging.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/core.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/core.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/dbunit.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/dbunit.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/dom4j.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/dom4j.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/drools-compiler.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/drools-compiler.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/drools-core.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/drools-core.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/easymock.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/easymock.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/ehcache-1.2.3.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/ehcache-1.2.3.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/ejb-api.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/ejb-api.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/el-api.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/el-api.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/groovy-all.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/groovy-all.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/gwt-servlet.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/gwt-servlet.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/hibernate-annotations.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/hibernate-annotations.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/hibernate-commons-annotations.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/hibernate-commons-annotations.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/hibernate-entitymanager.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/hibernate-entitymanager.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/hibernate-search.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/hibernate-search.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/hibernate-validator.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/hibernate-validator.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/hibernate.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/hibernate.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/hibernate3.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/hibernate3.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/htmlcleaner1_6.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/htmlcleaner1_6.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/itext.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/itext.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/janino.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/janino.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/javassist.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/javassist.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jaxb-api.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jaxb-api.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jaxws-api.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jaxws-api.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jboss-aop.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jboss-aop.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jboss-cache.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jboss-cache.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jboss-common-core.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jboss-common-core.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jboss-dependency.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jboss-dependency.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jboss-deployers-client-spi.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jboss-deployers-client-spi.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jboss-deployers-core-spi.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jboss-deployers-core-spi.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jboss-el.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jboss-el.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jboss-embedded-api.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jboss-embedded-api.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jboss-jmx.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jboss-jmx.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jboss-kernel.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jboss-kernel.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jboss-logging-spi.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jboss-logging-spi.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jboss-seam-debug.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jboss-seam-debug.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jboss-seam-gen.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jboss-seam-gen.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jboss-seam-ioc.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jboss-seam-ioc.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jboss-seam-mail.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jboss-seam-mail.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jboss-seam-pdf.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jboss-seam-pdf.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jboss-seam-remoting.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jboss-seam-remoting.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jboss-seam-ui.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jboss-seam-ui.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jboss-seam.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jboss-seam.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jboss-system.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jboss-system.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jbossxb.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jbossxb.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jbpm-jpdl.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jbpm-jpdl.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jcommon.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jcommon.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jdom.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jdom.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jericho-html-2.5.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jericho-html-2.5.jar
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jfreechart.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jfreechart.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jgroups.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jgroups.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jms.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jms.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jsf-api.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jsf-api.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jsf-facelets.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jsf-facelets.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jsf-impl.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jsf-impl.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jsp-api.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jsp-api.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jsr173_api.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jsr173_api.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jsr181-api.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jsr181-api.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jsr250-api.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jsr250-api.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jstl.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jstl.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/jta.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/jta.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/let-tag.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/let-tag.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/log4j.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/log4j.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/lucene-core.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/lucene-core.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/mail.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/mail.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/meldware-mailapi.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/meldware-mailapi.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/meldware-mailjmx.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/meldware-mailjmx.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/mvel14.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/mvel14.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/mysql.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/mysql.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/persistence-api.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/persistence-api.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/portal-common-lib.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/portal-common-lib.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/portal-identity-lib.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/portal-identity-lib.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/portal-portlet-jsr168api-lib.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/portal-portlet-jsr168api-lib.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/portlet-api.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/portlet-api.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/richfaces-api.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/richfaces-api.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/richfaces-impl.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/richfaces-impl.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/richfaces-ui.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/richfaces-ui.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/rome-1.0RC1.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/rome-1.0RC1.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/saaj-api.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/saaj-api.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/servlet-api.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/servlet-api.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/shotoku-base.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/shotoku-base.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/spring.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/spring.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/src/jboss-seam-debug-sources.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/src/jboss-seam-debug-sources.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/src/jboss-seam-gen-sources.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/src/jboss-seam-gen-sources.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/src/jboss-seam-ioc-sources.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/src/jboss-seam-ioc-sources.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/src/jboss-seam-mail-sources.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/src/jboss-seam-mail-sources.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/src/jboss-seam-pdf-sources.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/src/jboss-seam-pdf-sources.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/src/jboss-seam-remoting-sources.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/src/jboss-seam-remoting-sources.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/src/jboss-seam-sources.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/src/jboss-seam-sources.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/src/jboss-seam-ui-sources.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/src/jboss-seam-ui-sources.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/standard.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/standard.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/test/hibernate-all.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/test/hibernate-all.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/test/jboss-embedded-all.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/test/jboss-embedded-all.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/test/thirdparty-all.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/test/thirdparty-all.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/testng.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/testng.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/urlrewritefilter.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/urlrewritefilter.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/velocity-1.5.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/velocity-1.5.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/lib/velocity-dep-1.5.jar
===================================================================
(Binary files differ)
Property changes on: feeds100P26/lib/velocity-dep-1.5.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/resources/META-INF/application.xml
===================================================================
--- feeds100P26/resources/META-INF/application.xml (rev 0)
+++ feeds100P26/resources/META-INF/application.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<application xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_5.xsd"
+ version="5">
+
+ <display-name>blog</display-name>
+
+ <!-- Seam and EL -->
+ <module>
+ <ejb>jboss-seam.jar</ejb>
+ </module>
+
+ <module>
+ <ejb>blog-impl.jar</ejb>
+ </module>
+
+ <module>
+ <ejb>blog-shotoku.jar</ejb>
+ </module>
+
+ <module>
+ <ejb>blog-portal.jar</ejb>
+ </module>
+
+ <module>
+ <web>
+ <web-uri>blog.war</web-uri>
+ <context-root>/feeds</context-root>
+ </web>
+ </module>
+
+ <module>
+ <web>
+ <web-uri>blog-portal.war</web-uri>
+ <context-root>/blog-portal</context-root>
+ </web>
+ </module>
+</application>
Added: feeds100P26/resources/META-INF/ejb-jar.xml
===================================================================
--- feeds100P26/resources/META-INF/ejb-jar.xml (rev 0)
+++ feeds100P26/resources/META-INF/ejb-jar.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
+ version="3.0">
+
+ <interceptors>
+ <interceptor>
+ <interceptor-class>org.jboss.seam.ejb.SeamInterceptor</interceptor-class>
+ </interceptor>
+ </interceptors>
+
+ <assembly-descriptor>
+ <interceptor-binding>
+ <ejb-name>*</ejb-name>
+ <interceptor-class>org.jboss.seam.ejb.SeamInterceptor</interceptor-class>
+ </interceptor-binding>
+ </assembly-descriptor>
+
+</ejb-jar>
\ No newline at end of file
Added: feeds100P26/resources/META-INF/jboss-app.xml
===================================================================
--- feeds100P26/resources/META-INF/jboss-app.xml (rev 0)
+++ feeds100P26/resources/META-INF/jboss-app.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE jboss-app
+ PUBLIC "-//JBoss//DTD J2EE Application 4.2//EN"
+ "http://www.jboss.org/j2ee/dtd/jboss-app_4_2.dtd">
+
+<jboss-app>
+ <loader-repository>
+ seam.jboss.org:loader=blog
+ </loader-repository>
+</jboss-app>
\ No newline at end of file
Added: feeds100P26/resources/META-INF/jbossblog.taglib.xml
===================================================================
--- feeds100P26/resources/META-INF/jbossblog.taglib.xml (rev 0)
+++ feeds100P26/resources/META-INF/jbossblog.taglib.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!DOCTYPE facelet-taglib PUBLIC
+ "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
+ "http://java.sun.com/dtd/facelet-taglib_1_0.dtd">
+<facelet-taglib>
+ <namespace>http://jboss.org/blog/tags</namespace>
+
+ <tag>
+ <tag-name>uniqueFeedNameValidator</tag-name>
+ <validator>
+ <validator-id>uniqueFeedNameValidator</validator-id>
+ </validator>
+ </tag>
+ <tag>
+ <tag-name>uniqueTemplateNameValidator</tag-name>
+ <validator>
+ <validator-id>uniqueTemplateNameValidator</validator-id>
+ </validator>
+ </tag>
+ <tag>
+ <tag-name>uniqueGroupNameValidator</tag-name>
+ <validator>
+ <validator-id>uniqueGroupNameValidator</validator-id>
+ </validator>
+ </tag>
+</facelet-taglib>
\ No newline at end of file
Added: feeds100P26/resources/META-INF/persistence-design.xml
===================================================================
--- feeds100P26/resources/META-INF/persistence-design.xml (rev 0)
+++ feeds100P26/resources/META-INF/persistence-design.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Persistence deployment descriptor for dev profile -->
+<persistence xmlns="http://java.sun.com/xml/ns/persistence"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
+ version="1.0">
+
+ <persistence-unit name="blog">
+ <provider>org.hibernate.ejb.HibernatePersistence</provider>
+ <jta-data-source>java:/blogDatasource</jta-data-source>
+ <class>org.jboss.blog.model.Group</class>
+ <class>org.jboss.blog.model.feed.Feed</class>
+ <class>org.jboss.blog.model.feed.RemoteFeed</class>
+ <class>org.jboss.blog.model.feed.AggregatedFeed</class>
+ <class>org.jboss.blog.model.feed.HighlightsFeed</class>
+ <class>org.jboss.blog.model.feed.IndividualPostsFeed</class>
+ <class>org.jboss.blog.model.feed.IndividualPostInfo</class>
+ <class>org.jboss.blog.model.Category</class>
+ <class>org.jboss.blog.model.Post</class>
+ <class>org.jboss.blog.model.Enclosure</class>
+ <class>org.jboss.blog.model.Image</class>
+ <class>org.jboss.blog.model.Template</class>
+ <class>org.jboss.blog.model.configuration.Configuration</class>
+ <class>org.jboss.blog.model.security.SecurityMapping</class>
+ <class>org.jboss.blog.model.security.SecurityGroup</class>
+ <class>org.jboss.blog.model.security.SecurityUser</class>
+ <class>org.jboss.blog.model.shotoku.ShotokuFeed</class>
+ <class>org.jboss.blog.model.log.PropositionsLog</class>
+ <properties>
+ <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
+ <property name="hibernate.hbm2ddl.auto" value="update"/>
+ <property name="hibernate.show_sql" value="false"/>
+ <property name="hibernate.format_sql" value="false"/>
+ <property name="jboss.entity.manager.factory.jndi.name" value="java:/blogEntityManagerFactory"/>
+ <property name="hibernate.connection.useUnicode" value="true" />
+ <property name="hibernate.connection.characterEncoding" value="UTF-8" />
+
+ <property name="hibernate.jdbc.batch_size" value="0" />
+
+ <property name="hibernate.cache.use_query_cache" value="true"/>
+ <property name="hibernate.cache.use_second_level_cache" value="true"/>
+ <property name="hibernate.cache.provider_class" value="org.hibernate.cache.EhCacheProvider" />
+ <property name="hibernate.cache.provider_configuration_file_resource_path" value="blog-ehcache.xml" />
+
+ <!-- TODO Search -->
+ <!-- use a file system based index
+ <property name="hibernate.search.default.directory_provider"
+ value="org.hibernate.search.store.FSDirectoryProvider"/> -->
+ <!-- directory where the indexes will be stored
+ <property name="hibernate.search.default.indexBase"
+ value="/Users/adamwarski/jboss/blog-index"/>
+
+ <property name="hibernate.ejb.event.post-insert"
+ value="org.hibernate.search.event.FullTextIndexEventListener"/>
+ <property name="hibernate.ejb.event.post-update"
+ value="org.hibernate.search.event.FullTextIndexEventListener"/>
+ <property name="hibernate.ejb.event.post-delete"
+ value="org.hibernate.search.event.FullTextIndexEventListener"/>-->
+ </properties>
+ </persistence-unit>
+
+</persistence>
Added: feeds100P26/resources/META-INF/persistence-dev.xml
===================================================================
--- feeds100P26/resources/META-INF/persistence-dev.xml (rev 0)
+++ feeds100P26/resources/META-INF/persistence-dev.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Persistence deployment descriptor for dev profile -->
+<persistence xmlns="http://java.sun.com/xml/ns/persistence"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
+ version="1.0">
+ <persistence-unit name="blog">
+ <provider>org.hibernate.ejb.HibernatePersistence</provider>
+ <jta-data-source>java:/blogDatasource</jta-data-source>
+ <class>org.jboss.blog.model.Group</class>
+ <class>org.jboss.blog.model.feed.Feed</class>
+ <class>org.jboss.blog.model.feed.RemoteFeed</class>
+ <class>org.jboss.blog.model.feed.AggregatedFeed</class>
+ <class>org.jboss.blog.model.feed.HighlightsFeed</class>
+ <class>org.jboss.blog.model.feed.IndividualPostsFeed</class>
+ <class>org.jboss.blog.model.feed.IndividualPostInfo</class>
+ <class>org.jboss.blog.model.Category</class>
+ <class>org.jboss.blog.model.Post</class>
+ <class>org.jboss.blog.model.Enclosure</class>
+ <class>org.jboss.blog.model.Image</class>
+ <class>org.jboss.blog.model.Template</class>
+ <class>org.jboss.blog.model.configuration.Configuration</class>
+ <class>org.jboss.blog.model.security.SecurityMapping</class>
+ <class>org.jboss.blog.model.security.SecurityGroup</class>
+ <class>org.jboss.blog.model.security.SecurityUser</class>
+ <class>org.jboss.blog.model.shotoku.ShotokuFeed</class>
+ <class>org.jboss.blog.model.log.PropositionsLog</class>
+ <properties>
+ <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
+ <property name="hibernate.hbm2ddl.auto" value="update"/>
+ <property name="hibernate.show_sql" value="false"/>
+ <property name="hibernate.format_sql" value="false"/>
+ <property name="jboss.entity.manager.factory.jndi.name" value="java:/blogEntityManagerFactory"/>
+ <property name="hibernate.connection.useUnicode" value="true" />
+ <property name="hibernate.connection.characterEncoding" value="UTF-8" />
+
+ <property name="hibernate.cache.use_query_cache" value="true"/>
+ <property name="hibernate.cache.use_second_level_cache" value="true"/>
+ <property name="hibernate.cache.provider_class" value="org.hibernate.cache.EhCacheProvider" />
+ <property name="hibernate.cache.provider_configuration_file_resource_path" value="blog-ehcache.xml" />
+
+ <!-- use a file system based index -->
+ <property name="hibernate.search.default.directory_provider"
+ value="org.hibernate.search.store.FSDirectoryProvider"/>
+ <!-- directory where the indexes will be stored -->
+ <property name="hibernate.search.default.indexBase"
+ value="/Users/adamwarski/jboss/blog-index"/>
+
+ <property name="hibernate.ejb.event.post-insert"
+ value="org.hibernate.search.event.FullTextIndexEventListener"/>
+ <property name="hibernate.ejb.event.post-update"
+ value="org.hibernate.search.event.FullTextIndexEventListener"/>
+ <property name="hibernate.ejb.event.post-delete"
+ value="org.hibernate.search.event.FullTextIndexEventListener"/>
+ </properties>
+ </persistence-unit>
+</persistence>
Added: feeds100P26/resources/META-INF/persistence-prod.xml
===================================================================
--- feeds100P26/resources/META-INF/persistence-prod.xml (rev 0)
+++ feeds100P26/resources/META-INF/persistence-prod.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Persistence deployment descriptor for prod profile -->
+<persistence xmlns="http://java.sun.com/xml/ns/persistence"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
+ version="1.0">
+ <persistence-unit name="blog">
+ <provider>org.hibernate.ejb.HibernatePersistence</provider>
+ <jta-data-source>java:/blogDatasource</jta-data-source>
+ <class>org.jboss.blog.model.Group</class>
+ <class>org.jboss.blog.model.feed.Feed</class>
+ <class>org.jboss.blog.model.feed.RemoteFeed</class>
+ <class>org.jboss.blog.model.feed.AggregatedFeed</class>
+ <class>org.jboss.blog.model.feed.HighlightsFeed</class>
+ <class>org.jboss.blog.model.feed.IndividualPostsFeed</class>
+ <class>org.jboss.blog.model.feed.IndividualPostInfo</class>
+ <class>org.jboss.blog.model.Category</class>
+ <class>org.jboss.blog.model.Post</class>
+ <class>org.jboss.blog.model.Enclosure</class>
+ <class>org.jboss.blog.model.Image</class>
+ <class>org.jboss.blog.model.Template</class>
+ <class>org.jboss.blog.model.configuration.Configuration</class>
+ <class>org.jboss.blog.model.security.SecurityMapping</class>
+ <class>org.jboss.blog.model.security.SecurityGroup</class>
+ <class>org.jboss.blog.model.security.SecurityUser</class>
+ <class>org.jboss.blog.model.shotoku.ShotokuFeed</class>
+ <class>org.jboss.blog.model.log.PropositionsLog</class>
+ <properties>
+ <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
+ <property name="hibernate.hbm2ddl.auto" value="update"/>
+ <property name="hibernate.show_sql" value="false"/>
+ <property name="hibernate.format_sql" value="false"/>
+ <property name="jboss.entity.manager.factory.jndi.name" value="java:/blogEntityManagerFactory"/>
+ <property name="hibernate.connection.useUnicode" value="true" />
+ <property name="hibernate.connection.characterEncoding" value="UTF-8" />
+
+ <property name="hibernate.cache.use_query_cache" value="true"/>
+ <property name="hibernate.cache.use_second_level_cache" value="true"/>
+ <property name="hibernate.cache.provider_class" value="org.hibernate.cache.EhCacheProvider" />
+ <property name="hibernate.cache.provider_configuration_file_resource_path" value="blog-ehcache.xml" />
+
+ <!-- use a file system based index -->
+ <property name="hibernate.search.default.directory_provider"
+ value="org.hibernate.search.store.FSDirectoryProvider"/>
+ <!-- directory where the indexes will be stored -->
+ <property name="hibernate.search.default.indexBase"
+ value="/tmp/blog-index"/>
+
+ <property name="hibernate.ejb.event.post-insert"
+ value="org.hibernate.search.event.FullTextIndexEventListener"/>
+ <property name="hibernate.ejb.event.post-update"
+ value="org.hibernate.search.event.FullTextIndexEventListener"/>
+ <property name="hibernate.ejb.event.post-delete"
+ value="org.hibernate.search.event.FullTextIndexEventListener"/>
+ </properties>
+ </persistence-unit>
+</persistence>
Added: feeds100P26/resources/META-INF/security.drl
===================================================================
--- feeds100P26/resources/META-INF/security.drl (rev 0)
+++ feeds100P26/resources/META-INF/security.drl 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,207 @@
+package FeedsPermissions;
+
+import java.util.ArrayList;
+
+import org.jboss.seam.security.PermissionCheck;
+import org.jboss.seam.security.Role;
+
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.Group;
+import org.jboss.blog.model.security.FeedsSecurityRole;
+import org.jboss.blog.session.security.FeedsCombinedRole;
+
+rule CanDoAnything
+when
+ c: PermissionCheck()
+ FeedsCombinedRole(role == FeedsSecurityRole.ADMIN)
+then
+ c.grant();
+end;
+
+rule CanAddFeed
+when
+ c: PermissionCheck(name == "feed", action == "add") and
+ group : Group() and
+ FeedsCombinedRole(role == FeedsSecurityRole.GROUP_ADMIN, id == group.id)
+then
+ c.grant();
+end;
+
+rule CanProposeFeed
+when
+ c: PermissionCheck(name == "feed", action == "add") and
+ Feed(accepted == false)
+then
+ c.grant();
+end;
+
+rule CanEditFeed
+when
+ c: PermissionCheck(name == "feed", action == "edit") and
+ (
+ (
+ group : Group() and
+ feed : Feed(group == group) and
+ FeedsCombinedRole(role == FeedsSecurityRole.FEED_ADMIN, id == feed.id)
+ ) or
+ (
+ group : Group() and
+ FeedsCombinedRole(role == FeedsSecurityRole.GROUP_ADMIN, id == group.id)
+ )
+ )
+then
+ c.grant();
+end;
+
+rule CanDeleteUnacceptedFeed
+when
+ c: PermissionCheck(name == "feed", action == "delete") and
+ Feed(accepted == false) and
+ group : Group() and
+ FeedsCombinedRole(role == FeedsSecurityRole.GROUP_ADMIN, id == group.id)
+then
+ c.grant();
+end;
+
+rule CanAddGroup
+when
+ c: PermissionCheck(name == "group", action == "add") and
+ FeedsCombinedRole(role == FeedsSecurityRole.GROUP_ADMIN)
+then
+ c.grant();
+end;
+
+rule CanEditGroup
+when
+ c: PermissionCheck(name == "group", action == "edit") and
+ group : Group() and
+ FeedsCombinedRole(role == FeedsSecurityRole.GROUP_ADMIN, id == group.id)
+then
+ c.grant();
+end;
+
+// Security-management
+
+rule CanAddOrDeleteSecurityGroupOrUser
+when
+ (
+ c: PermissionCheck(name == "security_group", action == "add") or
+ c: PermissionCheck(name == "security_user", action == "add") or
+ c: PermissionCheck(name == "security_group", action == "delete") or
+ c: PermissionCheck(name == "security_user", action == "delete")
+ ) and
+ (
+ (
+ role : FeedsSecurityRole(this == FeedsSecurityRole.FEED_ADMIN) and
+ feed : Feed() and
+ group : Group() from feed.group and
+ FeedsCombinedRole(role == FeedsSecurityRole.GROUP_ADMIN, id == group.id)
+ ) or
+ (
+ role : FeedsSecurityRole(this == FeedsSecurityRole.GROUP_ADMIN) and
+ group : Group() and
+ FeedsCombinedRole(role == FeedsSecurityRole.GROUP_ADMIN, id == group.id)
+ ) or
+ (
+ role : FeedsSecurityRole(this == FeedsSecurityRole.VIEW) and
+ feed : Feed() and
+ FeedsCombinedRole(role == FeedsSecurityRole.VIEW, id == feed.id)
+ )
+ )
+then
+ c.grant();
+end;
+
+// View-related rules
+
+rule CanViewGroupsManagement
+when
+ c: PermissionCheck(name == "management_groups", action == "view") and
+ FeedsCombinedRole(role == FeedsSecurityRole.GROUP_ADMIN)
+then
+ c.grant();
+end;
+
+rule CanViewGroupManagement
+when
+ c: PermissionCheck(name == "management_group", action == "view") and
+ (
+ (
+ feeds : ArrayList() and
+ feed : Feed() from feeds and
+ FeedsCombinedRole(role == FeedsSecurityRole.FEED_ADMIN, id == feed.id)
+ ) or
+ (
+ group : Group() and
+ FeedsCombinedRole(role == FeedsSecurityRole.GROUP_ADMIN, id == group.id)
+ )
+ )
+then
+ c.grant();
+end;
+
+rule CanViewSecurity
+when
+ c: PermissionCheck(name == "security", action == "view") and
+ (
+ FeedsCombinedRole(role == FeedsSecurityRole.GROUP_ADMIN)
+ )
+then
+ c.grant();
+end;
+
+rule CanViewManagement
+when
+ c: PermissionCheck(name == "management", action == "view") and
+ (
+ FeedsCombinedRole(role == FeedsSecurityRole.FEED_ADMIN) or
+ FeedsCombinedRole(role == FeedsSecurityRole.GROUP_ADMIN)
+ )
+then
+ c.grant();
+end;
+
+rule CanViewUserAccount
+when
+ c: PermissionCheck(name == "useraccount", action == "view") and
+ FeedsCombinedRole(role == FeedsSecurityRole.VIEW)
+then
+ c.grant();
+end;
+
+rule CanAddAnyFeed
+when
+ c: PermissionCheck(name == "feed", action == "add_any") and
+ FeedsCombinedRole(role == FeedsSecurityRole.GROUP_ADMIN)
+then
+ c.grant();
+end;
+
+// Feed-viewing
+
+rule CanViewFeed
+when
+ c: PermissionCheck(name == "feed", action == "view") and
+ (
+ Feed(feedRestricted == false) or
+ (
+ feed : Feed(feedRestricted == true) and
+ FeedsCombinedRole(role == FeedsSecurityRole.VIEW, id == feed.id)
+ )
+ )
+then
+ c.grant();
+end;
+
+rule CanViewFeedWhenFeedAmin
+when
+ c: PermissionCheck(name == "feed", action == "view") and
+ feed : Feed(feedRestricted == true) and
+ group : Group() from feed.group and
+ (
+ FeedsCombinedRole(role == FeedsSecurityRole.FEED_ADMIN, id == feed.id) or
+ FeedsCombinedRole(role == FeedsSecurityRole.GROUP_ADMIN, id == group.id)
+ )
+then
+ c.grant();
+end;
\ No newline at end of file
Added: feeds100P26/resources/WEB-INF/components.xml
===================================================================
--- feeds100P26/resources/WEB-INF/components.xml (rev 0)
+++ feeds100P26/resources/WEB-INF/components.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<components xmlns="http://jboss.com/products/seam/components"
+ xmlns:core="http://jboss.com/products/seam/core"
+ xmlns:persistence="http://jboss.com/products/seam/persistence"
+ xmlns:async="http://jboss.com/products/seam/async"
+ xmlns:drools="http://jboss.com/products/seam/drools"
+ xmlns:bpm="http://jboss.com/products/seam/bpm"
+ xmlns:security="http://jboss.com/products/seam/security"
+ xmlns:web="http://jboss.com/products/seam/web"
+ xmlns:navigation="http://jboss.com/products/seam/navigation"
+ xmlns:mail="http://jboss.com/products/seam/mail"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation=
+ "http://jboss.com/products/seam/core http://jboss.com/products/seam/core-2.0.xsd
+ http://jboss.com/products/seam/async http://jboss.com/products/seam/async-2.0.xsd
+ http://jboss.com/products/seam/persistence http://jboss.com/products/seam/persistence-2.0.xsd
+ http://jboss.com/products/seam/drools http://jboss.com/products/seam/drools-2.0.xsd
+ http://jboss.com/products/seam/bpm http://jboss.com/products/seam/bpm-2.0.xsd
+ http://jboss.com/products/seam/web http://jboss.com/products/seam/web-2.0.xsd
+ http://jboss.com/products/seam/security http://jboss.com/products/seam/security-2.0.xsd
+ http://jboss.com/products/seam/mail http://jboss.com/products/seam/mail-2.0.xsd
+ http://jboss.com/products/seam/navigation http://jboss.com/products/seam/navigation-2.0.xsd
+ http://jboss.com/products/seam/components http://jboss.com/products/seam/components-2.0.xsd">
+
+ <core:init debug="@debug@" jndi-pattern="@jndiPattern@"/>
+
+ <core:manager concurrent-request-timeout="500"
+ conversation-timeout="300000"
+ conversation-id-parameter="cid"/>
+
+ <persistence:managed-persistence-context name="entityManager"
+ auto-create="true"
+ persistence-unit-jndi-name="java:/blogEntityManagerFactory"/>
+
+ <security:identity authenticate-method="#{authenticator.authenticate}"
+ security-rules="#{securityRules}" />
+
+ <async:thread-pool-dispatcher />
+
+ <drools:rule-base name="securityRules">
+ <drools:rule-files>
+ <value>/META-INF/security.drl</value>
+ </drools:rule-files>
+ </drools:rule-base>
+
+ <event type="org.jboss.seam.notLoggedIn">
+ <action execute="#{redirect.captureCurrentView}"/>
+ </event>
+ <event type="org.jboss.seam.postAuthenticate">
+ <action execute="#{redirect.returnToCapturedView}"/>
+ </event>
+
+ <event type="org.jboss.blog.captureView">
+ <action execute="#{redirect.captureCurrentView}"/>
+ </event>
+ <event type="org.jboss.blog.restoreView">
+ <action execute="#{redirect.returnToCapturedView}"/>
+ </event>
+
+ <mail:mail-session host="localhost" port="25" />
+
+ <web:context-filter url-pattern="/feeds.seam" />
+
+ <navigation:pages https-port="8443" http-port="8080" />
+
+ <component name="linkService">
+ <property name="serverAddress">http://localhost:8080</property>
+ <property name="contextName">feeds</property>
+ </component>
+</components>
Added: feeds100P26/resources/WEB-INF/faces-config.xml
===================================================================
--- feeds100P26/resources/WEB-INF/faces-config.xml (rev 0)
+++ feeds100P26/resources/WEB-INF/faces-config.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,14 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<faces-config version="1.2"
+ xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">
+
+ <application>
+ <locale-config>
+ <default-locale>en</default-locale>
+ </locale-config>
+ <view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
+ </application>
+
+</faces-config>
Added: feeds100P26/resources/WEB-INF/pages.xml
===================================================================
--- feeds100P26/resources/WEB-INF/pages.xml (rev 0)
+++ feeds100P26/resources/WEB-INF/pages.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,483 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<pages xmlns="http://jboss.com/products/seam/pages"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.0.xsd"
+ no-conversation-view-id="/home.xhtml"
+ login-view-id="/security/login.xhtml">
+
+ <!-- Global: security and group mod -->
+
+ <page view-id="*" scheme="http">
+ <navigation from-action="#{identity.logout}">
+ <redirect view-id="/home.xhtml"/>
+ </navigation>
+ <navigation from-action="#{groupMod.add}">
+ <begin-conversation nested="true" flush-mode="manual" />
+ <raise-event type="org.jboss.blog.captureView" />
+ <redirect view-id="/manage/group/group_add.xhtml" />
+ </navigation>
+ <navigation from-action="#{groupMod.cancel}">
+ <end-conversation />
+ <raise-event type="org.jboss.blog.restoreView" />
+ </navigation>
+ </page>
+
+ <!-- Security -->
+
+ <page view-id="/security/login.xhtml" scheme="https">
+ <navigation from-action="#{identity.login}">
+ <rule if="#{identity.loggedIn}">
+ <redirect view-id="/home.xhtml"/>
+ </rule>
+ </navigation>
+ </page>
+
+ <page view-id="/security/account.xhtml" login-required="true" />
+
+ <!-- View feeds -->
+
+ <page view-id="/home.xhtml" />
+
+ <page view-id="/view/feed.xhtml">
+ <param name="name" converterId="feedConverter" value="#{feedView.feed}" />
+ <param name="from" value="#{feedView.from}" />
+
+ <restrict>#{identity.hasPermission('feed', 'view', feedView.feed)}</restrict>
+ </page>
+
+ <page view-id="/view/post.xhtml">
+ <param name="post" converterId="postConverter" value="#{postView.post}" />
+ <navigation from-action="#{postView.delete}">
+ <redirect view-id="/view/feed.xhtml">
+ <param name="name" value="#{postView.post.feed.name}" />
+ </redirect>
+ </navigation>
+
+ <restrict>#{identity.hasPermission('feed', 'view', postView.post.feed)}</restrict>
+ </page>
+
+ <!-- Search -->
+
+ <page view-id="/search/search.xhtml">
+ <param name="query" value="#{postSearch.query}" />
+ <param name="from" value="#{postSearch.from}" />
+
+ <action execute="#{postSearch.search}" />
+ </page>
+
+ <!-- Manage main -->
+
+ <page view-id="/manage/index.xhtml" login-required="true">
+ <restrict>#{identity.hasPermission('management', 'view')}</restrict>
+ </page>
+
+ <!-- Manage feeds -->
+
+ <page view-id="/manage/feed_add.xhtml" conversation-required="true" login-required="true">
+ <navigation from-action="#{feedMod.saveNew}">
+ <end-conversation />
+ <redirect view-id="/manage/index.xhtml" />
+ </navigation>
+ </page>
+
+ <page view-id="/manage/feed_propose.xhtml" conversation-required="true" login-required="true">
+ <navigation from-action="#{feedMod.saveNew}">
+ <end-conversation />
+ <raise-event type="org.jboss.blog.feed.proposed" />
+ <redirect view-id="/home.xhtml" />
+ </navigation>
+ </page>
+
+ <page view-id="/manage/feed_edit.xhtml" login-required="true">
+ <begin-conversation flush-mode="manual" join="true" />
+ <param name="name" converterId="feedConverter" value="#{feedMod.feed}" />
+ <restrict>#{identity.hasPermission('feed', 'edit', feedMod.feed, feedMod.feed.group)}</restrict>
+ <navigation from-action="#{feedMod.saveExisting}">
+ <end-conversation />
+ <redirect view-id="/manage/index.xhtml" />
+ </navigation>
+ </page>
+
+ <page view-id="/manage/feed_delete.xhtml" login-required="true">
+ <param name="name" converterId="feedConverter" value="#{feedMod.feed}" />
+ <restrict>#{identity.hasPermission('feed', 'delete', feedMod.feed, feedMod.feed.group)}</restrict>
+ <navigation from-action="#{feedMod.delete}">
+ <redirect view-id="/manage/index.xhtml" />
+ </navigation>
+ </page>
+
+ <!-- Manage propositions -->
+
+ <page view-id="/manage/proposition/proposition_accept_1.xhtml" login-required="true">
+ <restrict>#{identity.hasPermission('feed', 'edit', feedMod.feed, feedMod.feed.group)}</restrict>
+ <begin-conversation flush-mode="manual" join="true" />
+ <param name="name" converterId="feedConverter" value="#{feedMod.feed}" />
+ <navigation from-action="#{remoteFeedMod.saveExisting}">
+ <redirect view-id="/manage/proposition/proposition_accept_2.xhtml" />
+ </navigation>
+ <navigation from-action="#{remoteFeedMod.savePartial}">
+ <redirect view-id="/manage/proposition/proposition_accept_2.xhtml" />
+ </navigation>
+ </page>
+
+ <page view-id="/manage/proposition/proposition_accept_2.xhtml" login-required="true" conversation-required="true">
+ <restrict>#{identity.hasPermission('feed', 'edit', feedMod.feed, feedMod.feed.group)}</restrict>
+ <navigation from-action="#{feedMod.saveExisting}">
+ <raise-event type="org.jboss.blog.feed.accept" />
+ <end-conversation />
+ <redirect view-id="/manage/proposition/proposition_list.xhtml" />
+ </navigation>
+ </page>
+
+ <!-- Manage remote feeds -->
+
+ <page view-id="/manage/remote/remote_add.xhtml" login-required="true">
+ <begin-conversation flush-mode="manual" join="true" />
+ <navigation from-action="#{remoteFeedMod.saveNew}">
+ <redirect view-id="/manage/feed_add.xhtml" />
+ </navigation>
+ </page>
+
+ <page view-id="/manage/remote/remote_edit.xhtml" login-required="true">
+ <begin-conversation flush-mode="manual" join="true" />
+ <param name="name" converterId="feedConverter" value="#{feedMod.feed}" />
+ <restrict>#{identity.hasPermission('feed', 'edit', feedMod.feed, feedMod.feed.group)}</restrict>
+ <navigation from-action="#{remoteFeedMod.saveExisting}">
+ <end-conversation />
+ <redirect view-id="/manage/index.xhtml" />
+ </navigation>
+ <navigation from-action="#{remoteFeedMod.savePartial}">
+ <end-conversation />
+ <redirect view-id="/manage/index.xhtml" />
+ </navigation>
+ </page>
+
+ <page view-id="/manage/remote/remote_propose.xhtml" login-required="true">
+ <begin-conversation flush-mode="manual" join="true" />
+ <action execute="#{remoteFeedMod.unsetAccepted}" />
+ <navigation from-action="#{remoteFeedMod.saveNew}">
+ <redirect view-id="/manage/feed_propose.xhtml" />
+ </navigation>
+ </page>
+
+ <!-- Manage aggregated feeds -->
+
+ <page view-id="/manage/aggregated/aggregated_add.xhtml" login-required="true">
+ <begin-conversation flush-mode="manual" join="true" />
+ <navigation from-action="#{aggregatedFeedMod.saveNew}">
+ <redirect view-id="/manage/feed_add.xhtml" />
+ </navigation>
+
+ <!-- Should be done using a wildcard, but they aren't supported -->
+ <navigation from-action="#{filterAdd.addToList(aggregatedFeedMod.globalFilters)}">
+ <raise-event type="org.jboss.blog.captureView" />
+ <redirect view-id="/manage/aggregated/filter_add.xhtml" />
+ </navigation>
+ <navigation from-action="#{filterAdd.addToList(aggregatedFeedMod.selectedFeedsFilters[feed])}">
+ <raise-event type="org.jboss.blog.captureView" />
+ <redirect view-id="/manage/aggregated/filter_add.xhtml" />
+ </navigation>
+ <navigation from-action="#{filterAdd.addToList(aggregatedFeedMod.selectedGroupsFilters[group])}">
+ <raise-event type="org.jboss.blog.captureView" />
+ <redirect view-id="/manage/aggregated/filter_add.xhtml" />
+ </navigation>
+ </page>
+
+ <page view-id="/manage/aggregated/aggregated_edit.xhtml" login-required="true">
+ <begin-conversation flush-mode="manual" join="true" />
+ <param name="name" converterId="feedConverter" value="#{feedMod.feed}" />
+ <restrict>#{identity.hasPermission('feed', 'edit', feedMod.feed, feedMod.feed.group)}</restrict>
+ <navigation from-action="#{aggregatedFeedMod.saveExisting}">
+ <end-conversation />
+ <redirect view-id="/manage/index.xhtml" />
+ </navigation>
+
+ <!-- Should be done using a wildcard, but they aren't supported -->
+ <navigation from-action="#{filterAdd.addToList(aggregatedFeedMod.globalFilters)}">
+ <raise-event type="org.jboss.blog.captureView" />
+ <redirect view-id="/manage/aggregated/filter_add.xhtml" />
+ </navigation>
+ <navigation from-action="#{filterAdd.addToList(aggregatedFeedMod.selectedFeedsFilters[feed])}">
+ <raise-event type="org.jboss.blog.captureView" />
+ <redirect view-id="/manage/aggregated/filter_add.xhtml" />
+ </navigation>
+ <navigation from-action="#{filterAdd.addToList(aggregatedFeedMod.selectedGroupsFilters[group])}">
+ <raise-event type="org.jboss.blog.captureView" />
+ <redirect view-id="/manage/aggregated/filter_add.xhtml" />
+ </navigation>
+ </page>
+
+ <!-- Add filters -->
+
+ <page view-id="/manage/aggregated/filter_add.xhtml" conversation-required="true" login-required="true">
+ <!-- Should be done using a wildcard, but they aren't supported -->
+ <navigation from-action="#{filterAdd.add(filterAdd.podcastFilter)}">
+ <raise-event type="org.jboss.blog.restoreView" />
+ </navigation>
+ <navigation from-action="#{filterAdd.add(filterAdd.notPodcastFilter)}">
+ <raise-event type="org.jboss.blog.restoreView" />
+ </navigation>
+ <navigation from-action="#{filterAdd.add(filterAdd.authorRegexpFilter)}">
+ <raise-event type="org.jboss.blog.restoreView" />
+ </navigation>
+ <navigation from-action="#{filterAdd.add(filterAdd.categoryRegexpFilter)}">
+ <raise-event type="org.jboss.blog.restoreView" />
+ </navigation>
+ <navigation from-action="#{filterAdd.cancel}">
+ <raise-event type="org.jboss.blog.restoreView" />
+ </navigation>
+ </page>
+
+ <!-- Manage highlights feeds -->
+
+ <page view-id="/manage/highlights/highlights_add.xhtml" login-required="true">
+ <begin-conversation flush-mode="manual" join="true" />
+ <action execute="#{highlightsFeedMod.getHighlightsFeed}"/>
+
+ <navigation>
+ <redirect view-id="/manage/feed_add.xhtml">
+ <message severity="INFO">#{messages['blog.feed.highlights.adding.info']}</message>
+ </redirect>
+ </navigation>
+ </page>
+
+ <page view-id="/manage/highlights/highlights_edit.xhtml" login-required="true">
+ <begin-conversation flush-mode="manual" join="true" />
+ <param name="name" converterId="feedConverter" value="#{feedMod.feed}" />
+ <restrict>#{identity.hasPermission('feed', 'edit', feedMod.feed, feedMod.feed.group)}</restrict>
+ <navigation from-action="#{highlightsFeedMod.saveExisting}">
+ <end-conversation />
+ <redirect view-id="/manage/index.xhtml" />
+ </navigation>
+ </page>
+
+ <page view-id="/manage/highlights/post_add.xhtml" login-required="true">
+ <begin-conversation flush-mode="manual" join="true" />
+ <param name="post" converterId="postConverter" value="#{highlightsFeedMod.post}" />
+ <restrict>#{identity.hasPermission('management', 'view')}</restrict>
+ <navigation from-action="#{highlightsFeedMod.addPost}">
+ <end-conversation />
+ <redirect view-id="/manage/highlights/highlights_edit.xhtml">
+ <param name="name" value="#{highlightsFeedMod.selectedFeed.name}" />
+ </redirect>
+ </navigation>
+ </page>
+
+ <!-- Manage individual posts feeds -->
+
+ <page view-id="/manage/individual/individual_add.xhtml" login-required="true">
+ <begin-conversation flush-mode="manual" join="true" />
+ <!-- Initializing the new feed, if not yet initialized -->
+ <action execute="#{individualFeedMod.getIndividualPostsFeed}" />
+ <navigation from-action="#{feedMod.saveNew}">
+ <end-conversation before-redirect="true" />
+ <redirect view-id="/manage/individual/individual_edit.xhtml" />
+ </navigation>
+ </page>
+
+ <page view-id="/manage/individual/individual_edit.xhtml" login-required="true">
+ <begin-conversation flush-mode="manual" join="true" />
+ <param name="name" converterId="feedConverter" value="#{feedMod.feed}" />
+ <param name="from" value="#{individualFeedMod.from}" />
+ <restrict>#{identity.hasPermission('feed', 'edit', feedMod.feed, feedMod.feed.group)}</restrict>
+ <navigation from-action="#{individualFeedMod.saveExisting}">
+ <end-conversation />
+ <redirect view-id="/manage/index.xhtml" />
+ </navigation>
+ </page>
+
+ <page view-id="/manage/individual/post_add.xhtml" login-required="true" conversation-required="true">
+ <restrict>#{identity.hasPermission('feed', 'edit', feedMod.feed, feedMod.feed.group)}</restrict>
+ <navigation from-action="#{individualFeedMod.addPost}">
+ <redirect view-id="/manage/individual/individual_edit.xhtml" />
+ </navigation>
+ <navigation from-action="#{individualFeedMod.reset}">
+ <redirect view-id="/manage/individual/individual_edit.xhtml" />
+ </navigation>
+ </page>
+
+ <!-- Manage groups -->
+
+ <page view-id="/manage/group/group_list.xhtml" login-required="true">
+ <restrict>#{identity.hasPermission('management_groups', 'view')}</restrict>
+ <param name="id" converterId="groupConverter" value="#{groupMod.group}" />
+ <navigation from-action="#{groupMod.edit}">
+ <begin-conversation nested="true" flush-mode="manual" />
+ <raise-event type="org.jboss.blog.captureView" />
+ <redirect view-id="/manage/group/group_edit.xhtml">
+ <param name="id" converterId="groupConverter" value="#{groupMod.group}" />
+ </redirect>
+ </navigation>
+ </page>
+
+ <page view-id="/manage/group/group_add.xhtml" login-required="true">
+ <restrict>#{identity.hasPermission('group', 'add')}</restrict>
+ <navigation from-action="#{groupMod.saveNew}">
+ <end-conversation />
+ <raise-event type="org.jboss.blog.restoreView" />
+ </navigation>
+ </page>
+
+ <page view-id="/manage/group/group_edit.xhtml" login-required="true">
+ <param name="id" converterId="groupConverter" value="#{groupMod.group}" />
+ <restrict>#{identity.hasPermission('group', 'edit', groupMod.group)}</restrict>
+ <navigation from-action="#{groupMod.saveExisting}">
+ <end-conversation />
+ <raise-event type="org.jboss.blog.restoreView" />
+ </navigation>
+ </page>
+
+ <page view-id="/manage/group/group_delete.xhtml" login-required="true">
+ <param name="id" converterId="groupConverter" value="#{groupMod.group}" />
+ <restrict>#{identity.hasPermission('group', 'delete', groupMod.group)}</restrict>
+ <navigation from-action="#{groupMod.delete}">
+ <redirect view-id="/manage/group/group_list.xhtml" />
+ </navigation>
+ </page>
+
+ <!-- Manage templates -->
+
+ <page view-id="/manage/template/template_list.xhtml" login-required="true">
+ <restrict>#{identity.hasPermission('management_template', 'view')}</restrict>
+ </page>
+
+ <page view-id="/manage/template/template_add.xhtml" login-required="true">
+ <restrict>#{identity.hasPermission('template', 'add')}</restrict>
+ <begin-conversation flush-mode="manual" join="true" />
+ <navigation from-action="#{templateMod.saveNew}">
+ <end-conversation />
+ <redirect view-id="/manage/template/template_list.xhtml" />
+ </navigation>
+ </page>
+
+ <page view-id="/manage/template/template_edit.xhtml" login-required="true">
+ <begin-conversation flush-mode="manual" join="true" />
+ <param name="id" converterId="templateConverter" value="#{templateMod.template}" />
+ <restrict>#{identity.hasPermission('template', 'edit', templateMod.template)}</restrict>
+ <navigation from-action="#{templateMod.saveExisting}">
+ <end-conversation />
+ <redirect view-id="/manage/template/template_list.xhtml" />
+ </navigation>
+ </page>
+
+ <page view-id="/manage/template/template_delete.xhtml" login-required="true">
+ <param name="id" converterId="templateConverter" value="#{templateMod.template}" />
+ <restrict>#{identity.hasPermission('template', 'delete', templateMod.template)}</restrict>
+ <navigation from-action="#{templateMod.delete}">
+ <redirect view-id="/manage/template/template_list.xhtml" />
+ </navigation>
+ </page>
+
+ <!-- Manage updates -->
+
+ <page view-id="/manage/update_manager.xhtml" login-required="true">
+ <restrict>#{identity.hasPermission('admin', '')}</restrict>
+ </page>
+
+ <!-- Manage configuration -->
+
+ <page view-id="/manage/configuration_manager.xhtml" login-required="true">
+ <begin-conversation flush-mode="manual" join="true" />
+ <restrict>#{identity.hasPermission('admin', '')}</restrict>
+ </page>
+
+ <!-- Manage security -->
+
+ <page view-id="/security/security_manager.xhtml">
+ <restrict>#{identity.hasPermission('security', 'view')}</restrict>
+ <param name="securityGroup" converterId="securityGroupConverter" value="#{securityMod.restrictedSecurityGroup}" />
+ <param name="securityUser" converterId="securityUserConverter" value="#{securityMod.restrictedSecurityUser}" />
+ <param name="group" converterId="groupConverter" value="#{securityMod.group}" />
+ <param name="feed" converterId="feedConverter" value="#{securityMod.feed}" />
+ <param name="role" converterId="securityRoleConverter" value="#{securityMod.role}" />
+ </page>
+
+ <page view-id="/security/security_group_add.xhtml">
+ <restrict>#{identity.hasPermission('security', 'view')}</restrict>
+ <param name="group" converterId="groupConverter" value="#{securityMod.group}" />
+ <param name="feed" converterId="feedConverter" value="#{securityMod.feed}" />
+ <param name="role" converterId="securityRoleConverter" value="#{securityMod.role}" />
+
+ <navigation from-action="#{securityMod.addSecurityGroup}">
+ <redirect view-id="/security/security_manager.xhtml" />
+ </navigation>
+ </page>
+
+ <page view-id="/security/security_user_add.xhtml">
+ <restrict>#{identity.hasPermission('security', 'view')}</restrict>
+ <param name="group" converterId="groupConverter" value="#{securityMod.group}" />
+ <param name="feed" converterId="feedConverter" value="#{securityMod.feed}" />
+ <param name="role" converterId="securityRoleConverter" value="#{securityMod.role}" />
+
+ <param name="from" value="#{securityUserSelect.from}" />
+ <param name="filter" value="#{securityUserSelect.filter}" />
+
+ <navigation from-action="#{securityMod.addSecurityUser}">
+ <redirect view-id="/security/security_manager.xhtml" />
+ </navigation>
+
+ <navigation>
+ <rule if-outcome="search">
+ <redirect />
+ </rule>
+ </navigation>
+ </page>
+
+ <!-- Exceptions -->
+
+ <!-- TODO add in 2.0.2: log="false" -->
+ <exception class="org.jboss.blog.session.exceptions.FeedNotFoundRuntimeException">
+ <redirect view-id="/error/feed_error.xhtml">
+ <message>The requested feed hasn't been found.</message>
+ </redirect>
+ </exception>
+
+ <exception class="org.jboss.blog.session.exceptions.PostNotFoundRuntimeException">
+ <redirect view-id="/error/post_error.xhtml">
+ <message>The requested post hasn't been found.</message>
+ </redirect>
+ </exception>
+
+ <exception class="org.jboss.seam.framework.EntityNotFoundException">
+ <redirect view-id="/error/error.xhtml">
+ <message>Not found</message>
+ </redirect>
+ </exception>
+
+ <exception class="javax.persistence.EntityNotFoundException">
+ <redirect view-id="/error/error.xhtml">
+ <message>Not found</message>
+ </redirect>
+ </exception>
+
+ <exception class="javax.persistence.OptimisticLockException">
+ <end-conversation/>
+ <redirect view-id="/error/error.xhtml">
+ <message>Another user changed the same data, please try again</message>
+ </redirect>
+ </exception>
+
+ <exception class="org.jboss.seam.security.AuthorizationException">
+ <redirect view-id="/error/error.xhtml">
+ <message>You don't have permission to do this</message>
+ </redirect>
+ </exception>
+
+ <exception class="org.jboss.seam.security.NotLoggedInException">
+ <redirect view-id="/security/login.xhtml">
+ <message>Please log in first</message>
+ </redirect>
+ </exception>
+
+ <exception class="javax.faces.application.ViewExpiredException">
+ <redirect view-id="/error/error.xhtml">
+ <message>Your session has timed out, please try again</message>
+ </redirect>
+ </exception>
+
+ <exception>
+ <redirect view-id="/error/error.xhtml">
+ <message>Unexpected error, please try again</message>
+ </redirect>
+ </exception>
+</pages>
Added: feeds100P26/resources/WEB-INF/urlrewrite.xml
===================================================================
--- feeds100P26/resources/WEB-INF/urlrewrite.xml (rev 0)
+++ feeds100P26/resources/WEB-INF/urlrewrite.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 2.6//EN"
+ "http://tuckey.org/res/dtds/urlrewrite2.6.dtd">
+
+<!--
+
+ Configuration file for UrlRewriteFilter
+ http://tuckey.org/urlrewrite/
+
+-->
+<urlrewrite>
+ <!-- Main view -->
+
+ <rule>
+ <from>^/index.html$</from>
+ <to>/home.seam</to>
+ </rule>
+
+ <outbound-rule>
+ <from>^(.*)/feeds/home.seam$</from>
+ <to>$1/feeds/</to>
+ </outbound-rule>
+
+ <!-- Posts view -->
+
+ <rule>
+ <from>^/post/([a-z0-9_]*)(\?.+)?$</from>
+ <to>/view/post.seam?post=$1$2</to>
+ </rule>
+
+ <outbound-rule>
+ <from>^(.*)/feeds/view/post.seam\?post=(\w+)$</from>
+ <to>$1/feeds/post/$2</to>
+ </outbound-rule>
+
+ <outbound-rule>
+ <from>^(.*)/feeds/view/post.seam\?post=(\w+)&(.+)$</from>
+ <to>$1/feeds/post/$2?$3</to>
+ </outbound-rule>
+
+ <outbound-rule>
+ <from>^(.*)/feeds/view/post.seam\?cid=(\d+)&post=(\w+)(.*)$</from>
+ <to>$1/feeds/post/$3?cid=$2$4</to>
+ </outbound-rule>
+
+ <!-- Feeds -->
+
+ <rule>
+ <from>^/xml/([a-z0-9_]+)(\?.+)?$</from>
+ <to>/feeds.seam?name=$1</to>
+ </rule>
+
+ <outbound-rule>
+ <from>^(.*)/feeds/feeds.seam\?type=(\w+)&name=([a-z0-9_]*)$</from>
+ <to>$1/feeds/xml/$3?type=$2</to>
+ </outbound-rule>
+
+ <!-- Feed view -->
+
+ <rule>
+ <from>^/view/([a-z0-9_]+)(\?.+)?$</from>
+ <to>/view/feed.seam?name=$1$2</to>
+ </rule>
+
+ <outbound-rule>
+ <from>^(.*)/feeds/view/feed.seam\?(cid=\d+&)?(from=\d+)&name=([a-z0-9_]+)(.*)$</from>
+ <to>$1/feeds/view/$4?$2$3$5</to>
+ </outbound-rule>
+
+ <!-- Legacy Labs URLs -->
+
+ <rule>
+ <from>^/([a-zA-Z0-9_]+)/(rss2|atom|rdf)$</from>
+ <to type="permanent-redirect">/feeds/xml/$1?type=atom</to>
+ </rule>
+</urlrewrite>
+
Added: feeds100P26/resources/WEB-INF/web-design.xml
===================================================================
--- feeds100P26/resources/WEB-INF/web-design.xml (rev 0)
+++ feeds100P26/resources/WEB-INF/web-design.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,147 @@
+<?xml version="1.0" ?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+ version="2.5">
+
+ <!-- Ajax4jsf -->
+
+ <context-param>
+ <param-name>org.richfaces.SKIN</param-name>
+ <param-value>blueSky</param-value>
+ </context-param>
+
+ <context-param>
+ <param-name>sourceBasePath</param-name>
+ <param-value>/Users/adamwarski/jboss/jboss-design/server/default/deploy/blog.ear/blog.war</param-value>
+ </context-param>
+
+ <!-- URL rewrite -->
+
+ <filter>
+ <filter-name>UrlRewriteFilter</filter-name>
+ <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
+ <init-param>
+ <param-name>logLevel</param-name>
+ <param-value>WARN</param-value>
+ </init-param>
+ <init-param>
+ <param-name>statusEnabled</param-name>
+ <param-value>false</param-value>
+ </init-param>
+ </filter>
+ <filter-mapping>
+ <filter-name>UrlRewriteFilter</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+
+ <!-- Seam -->
+
+ <listener>
+ <listener-class>org.jboss.seam.servlet.SeamListener</listener-class>
+ </listener>
+
+ <filter>
+ <filter-name>Seam Filter</filter-name>
+ <filter-class>org.jboss.seam.servlet.SeamFilter</filter-class>
+ </filter>
+
+ <filter-mapping>
+ <filter-name>Seam Filter</filter-name>
+ <url-pattern>/*</url-pattern>
+ <dispatcher>ERROR</dispatcher>
+ <dispatcher>FORWARD</dispatcher>
+ <dispatcher>INCLUDE</dispatcher>
+ <dispatcher>REQUEST</dispatcher>
+ </filter-mapping>
+
+ <!-- Resources filter -->
+
+ <!--
+ <filter>
+ <filter-name>Resources Filter</filter-name>
+ <filter-class>org.jboss.shotoku.web.ResourcesFilter</filter-class>
+ </filter>
+
+ <filter-mapping>
+ <filter-name>Resources Filter</filter-name>
+ <url-pattern>/*</url-pattern>
+ <dispatcher>ERROR</dispatcher>
+ <dispatcher>FORWARD</dispatcher>
+ <dispatcher>INCLUDE</dispatcher>
+ <dispatcher>REQUEST</dispatcher>
+ </filter-mapping>
+ -->
+
+ <servlet>
+ <servlet-name>Seam Resource Servlet</servlet-name>
+ <servlet-class>org.jboss.seam.servlet.SeamResourceServlet</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>Seam Resource Servlet</servlet-name>
+ <url-pattern>/seam/resource/*</url-pattern>
+ </servlet-mapping>
+ <!-- Facelets development mode (disable in production) -->
+
+ <context-param>
+ <param-name>facelets.DEVELOPMENT</param-name>
+ <param-value>true</param-value>
+ </context-param>
+
+ <context-param>
+ <param-name>facelets.REFRESH_PERIOD</param-name>
+ <param-value>0</param-value>
+ </context-param>
+
+ <!--
+ <context-param>
+ <param-name>facelets.RESOURCE_RESOLVER</param-name>
+ <param-value>org.jboss.shotoku.web.FilesystemResourceResolver</param-value>
+ </context-param>
+ -->
+
+ <context-param>
+ <param-name>facelets.SKIP_COMMENTS</param-name>
+ <param-value>true</param-value>
+ </context-param>
+
+ <!-- JSF -->
+
+ <context-param>
+ <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
+ <param-value>.xhtml</param-value>
+ </context-param>
+
+ <servlet>
+ <servlet-name>Faces Servlet</servlet-name>
+ <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>Faces Servlet</servlet-name>
+ <url-pattern>*.seam</url-pattern>
+ </servlet-mapping>
+
+ <security-constraint>
+ <display-name>Restrict raw XHTML Documents</display-name>
+ <web-resource-collection>
+ <web-resource-name>XHTML</web-resource-name>
+ <url-pattern>*.xhtml</url-pattern>
+ </web-resource-collection>
+ <auth-constraint/>
+ </security-constraint>
+
+ <!-- Feeds servlet -->
+
+ <servlet>
+ <servlet-name>Feeds Servlet</servlet-name>
+ <servlet-class>org.jboss.blog.servlet.FeedsServlet</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>Feeds Servlet</servlet-name>
+ <url-pattern>/feeds.seam</url-pattern>
+ </servlet-mapping>
+</web-app>
Added: feeds100P26/resources/WEB-INF/web-dev.xml
===================================================================
--- feeds100P26/resources/WEB-INF/web-dev.xml (rev 0)
+++ feeds100P26/resources/WEB-INF/web-dev.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,143 @@
+<?xml version="1.0" ?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+ version="2.5">
+
+ <!-- Ajax4jsf -->
+
+ <context-param>
+ <param-name>org.richfaces.SKIN</param-name>
+ <param-value>blueSky</param-value>
+ </context-param>
+
+ <context-param>
+ <param-name>sourceBasePath</param-name>
+ <param-value>/Users/adamwarski/blog/view</param-value>
+ </context-param>
+
+ <!-- URL rewrite -->
+
+ <filter>
+ <filter-name>UrlRewriteFilter</filter-name>
+ <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
+ <init-param>
+ <param-name>logLevel</param-name>
+ <param-value>WARN</param-value>
+ </init-param>
+ <init-param>
+ <param-name>statusEnabled</param-name>
+ <param-value>false</param-value>
+ </init-param>
+ </filter>
+ <filter-mapping>
+ <filter-name>UrlRewriteFilter</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+
+ <!-- Seam -->
+
+ <listener>
+ <listener-class>org.jboss.seam.servlet.SeamListener</listener-class>
+ </listener>
+
+ <filter>
+ <filter-name>Seam Filter</filter-name>
+ <filter-class>org.jboss.seam.servlet.SeamFilter</filter-class>
+ </filter>
+
+ <filter-mapping>
+ <filter-name>Seam Filter</filter-name>
+ <url-pattern>/*</url-pattern>
+ <dispatcher>ERROR</dispatcher>
+ <dispatcher>FORWARD</dispatcher>
+ <dispatcher>INCLUDE</dispatcher>
+ <dispatcher>REQUEST</dispatcher>
+ </filter-mapping>
+
+ <!-- Resources filter -->
+
+ <filter>
+ <filter-name>Resources Filter</filter-name>
+ <filter-class>org.jboss.shotoku.web.ResourcesFilter</filter-class>
+ </filter>
+
+ <filter-mapping>
+ <filter-name>Resources Filter</filter-name>
+ <url-pattern>/*</url-pattern>
+ <dispatcher>ERROR</dispatcher>
+ <dispatcher>FORWARD</dispatcher>
+ <dispatcher>INCLUDE</dispatcher>
+ <dispatcher>REQUEST</dispatcher>
+ </filter-mapping>
+
+ <servlet>
+ <servlet-name>Seam Resource Servlet</servlet-name>
+ <servlet-class>org.jboss.seam.servlet.SeamResourceServlet</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>Seam Resource Servlet</servlet-name>
+ <url-pattern>/seam/resource/*</url-pattern>
+ </servlet-mapping>
+ <!-- Facelets development mode (disable in production) -->
+
+ <context-param>
+ <param-name>facelets.DEVELOPMENT</param-name>
+ <param-value>true</param-value>
+ </context-param>
+
+ <context-param>
+ <param-name>facelets.REFRESH_PERIOD</param-name>
+ <param-value>0</param-value>
+ </context-param>
+
+ <context-param>
+ <param-name>facelets.RESOURCE_RESOLVER</param-name>
+ <param-value>org.jboss.shotoku.web.FilesystemResourceResolver</param-value>
+ </context-param>
+
+ <context-param>
+ <param-name>facelets.SKIP_COMMENTS</param-name>
+ <param-value>true</param-value>
+ </context-param>
+
+ <!-- JSF -->
+
+ <context-param>
+ <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
+ <param-value>.xhtml</param-value>
+ </context-param>
+
+ <servlet>
+ <servlet-name>Faces Servlet</servlet-name>
+ <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>Faces Servlet</servlet-name>
+ <url-pattern>*.seam</url-pattern>
+ </servlet-mapping>
+
+ <security-constraint>
+ <display-name>Restrict raw XHTML Documents</display-name>
+ <web-resource-collection>
+ <web-resource-name>XHTML</web-resource-name>
+ <url-pattern>*.xhtml</url-pattern>
+ </web-resource-collection>
+ <auth-constraint/>
+ </security-constraint>
+
+ <!-- Feeds servlet -->
+
+ <servlet>
+ <servlet-name>Feeds Servlet</servlet-name>
+ <servlet-class>org.jboss.blog.servlet.FeedsServlet</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>Feeds Servlet</servlet-name>
+ <url-pattern>/feeds.seam</url-pattern>
+ </servlet-mapping>
+</web-app>
Added: feeds100P26/resources/WEB-INF/web-prod.xml
===================================================================
--- feeds100P26/resources/WEB-INF/web-prod.xml (rev 0)
+++ feeds100P26/resources/WEB-INF/web-prod.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,139 @@
+<?xml version="1.0" ?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+ version="2.5">
+
+ <!-- Ajax4jsf -->
+
+ <context-param>
+ <param-name>org.richfaces.SKIN</param-name>
+ <param-value>blueSky</param-value>
+ </context-param>
+
+ <!-- URL rewrite -->
+
+ <filter>
+ <filter-name>UrlRewriteFilter</filter-name>
+ <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
+ <init-param>
+ <param-name>logLevel</param-name>
+ <param-value>WARN</param-value>
+ </init-param>
+ <init-param>
+ <param-name>statusEnabled</param-name>
+ <param-value>false</param-value>
+ </init-param>
+ </filter>
+ <filter-mapping>
+ <filter-name>UrlRewriteFilter</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+
+ <!-- Resources filter -->
+
+ <filter>
+ <filter-name>Resources Filter</filter-name>
+ <filter-class>org.jboss.shotoku.web.ShotokuResourcesFilter</filter-class>
+ </filter>
+
+ <filter-mapping>
+ <filter-name>Resources Filter</filter-name>
+ <url-pattern>/*</url-pattern>
+ <dispatcher>ERROR</dispatcher>
+ <dispatcher>FORWARD</dispatcher>
+ <dispatcher>INCLUDE</dispatcher>
+ <dispatcher>REQUEST</dispatcher>
+ </filter-mapping>
+
+ <!-- Seam -->
+
+ <listener>
+ <listener-class>org.jboss.seam.servlet.SeamListener</listener-class>
+ </listener>
+
+ <filter>
+ <filter-name>Seam Filter</filter-name>
+ <filter-class>org.jboss.seam.servlet.SeamFilter</filter-class>
+ </filter>
+
+ <filter-mapping>
+ <filter-name>Seam Filter</filter-name>
+ <url-pattern>/*</url-pattern>
+ <dispatcher>ERROR</dispatcher>
+ <dispatcher>FORWARD</dispatcher>
+ <dispatcher>INCLUDE</dispatcher>
+ <dispatcher>REQUEST</dispatcher>
+ </filter-mapping>
+
+ <servlet>
+ <servlet-name>Seam Resource Servlet</servlet-name>
+ <servlet-class>org.jboss.seam.servlet.SeamResourceServlet</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>Seam Resource Servlet</servlet-name>
+ <url-pattern>/seam/resource/*</url-pattern>
+ </servlet-mapping>
+
+ <!-- Facelets development mode (disable in production) -->
+
+ <context-param>
+ <param-name>facelets.DEVELOPMENT</param-name>
+ <param-value>true</param-value>
+ </context-param>
+
+ <context-param>
+ <param-name>facelets.REFRESH_PERIOD</param-name>
+ <param-value>0</param-value>
+ </context-param>
+
+ <context-param>
+ <param-name>facelets.RESOURCE_RESOLVER</param-name>
+ <param-value>org.jboss.shotoku.web.ShotokuFilesystemResourceResolver</param-value>
+ </context-param>
+
+ <context-param>
+ <param-name>facelets.SKIP_COMMENTS</param-name>
+ <param-value>true</param-value>
+ </context-param>
+
+ <!-- JSF -->
+
+ <context-param>
+ <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
+ <param-value>.xhtml</param-value>
+ </context-param>
+
+ <servlet>
+ <servlet-name>Faces Servlet</servlet-name>
+ <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>Faces Servlet</servlet-name>
+ <url-pattern>*.seam</url-pattern>
+ </servlet-mapping>
+
+ <security-constraint>
+ <display-name>Restrict raw XHTML Documents</display-name>
+ <web-resource-collection>
+ <web-resource-name>XHTML</web-resource-name>
+ <url-pattern>*.xhtml</url-pattern>
+ </web-resource-collection>
+ <auth-constraint/>
+ </security-constraint>
+
+ <!-- Feeds servlet -->
+
+ <servlet>
+ <servlet-name>Feeds Servlet</servlet-name>
+ <servlet-class>org.jboss.blog.servlet.FeedsServlet</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>Feeds Servlet</servlet-name>
+ <url-pattern>/feeds.seam</url-pattern>
+ </servlet-mapping>
+</web-app>
Added: feeds100P26/resources/blog-design-ds.xml
===================================================================
--- feeds100P26/resources/blog-design-ds.xml (rev 0)
+++ feeds100P26/resources/blog-design-ds.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE datasources
+ PUBLIC "-//JBoss//DTD JBOSS JCA Config 1.5//EN"
+ "http://www.jboss.org/j2ee/dtd/jboss-ds_1_5.dtd">
+
+<datasources>
+
+ <local-tx-datasource>
+ <jndi-name>blogDatasource</jndi-name>
+ <connection-url>jdbc:hsqldb:${jboss.server.data.dir}${/}hypersonic${/}localDB</connection-url>
+ <driver-class>org.hsqldb.jdbcDriver</driver-class>
+ <user-name>sa</user-name>
+ <password></password>
+ </local-tx-datasource>
+
+</datasources>
+
Added: feeds100P26/resources/blog-dev-ds.xml
===================================================================
--- feeds100P26/resources/blog-dev-ds.xml (rev 0)
+++ feeds100P26/resources/blog-dev-ds.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE datasources
+ PUBLIC "-//JBoss//DTD JBOSS JCA Config 1.5//EN"
+ "http://www.jboss.org/j2ee/dtd/jboss-ds_1_5.dtd">
+
+<datasources>
+
+ <local-tx-datasource>
+ <jndi-name>blogDatasource</jndi-name>
+ <connection-url>jdbc:mysql:///blog?useUnicode=true&characterEncoding=UTF-8</connection-url>
+ <driver-class>com.mysql.jdbc.Driver</driver-class>
+ <user-name>root</user-name>
+ <password></password>
+<!--
+ <exception-sorter-class-name>
+ org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter
+ </exception-sorter-class-name>
+ <metadata>
+ <type-mapping>mySQL</type-mapping>
+ </metadata>
+-->
+ </local-tx-datasource>
+
+</datasources>
+
Added: feeds100P26/resources/blog-ehcache.xml
===================================================================
--- feeds100P26/resources/blog-ehcache.xml (rev 0)
+++ feeds100P26/resources/blog-ehcache.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,11 @@
+<ehcache>
+ <diskStore path="java.io.tmpdir"/>
+
+ <defaultCache
+ maxElementsInMemory="10000"
+ eternal="true"
+ overflowToDisk="true"
+ diskPersistent="false"
+ diskExpiryThreadIntervalSeconds="120"
+ memoryStoreEvictionPolicy="LRU" />
+</ehcache>
\ No newline at end of file
Added: feeds100P26/resources/blog-prod-ds.xml
===================================================================
--- feeds100P26/resources/blog-prod-ds.xml (rev 0)
+++ feeds100P26/resources/blog-prod-ds.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE datasources
+ PUBLIC "-//JBoss//DTD JBOSS JCA Config 1.5//EN"
+ "http://www.jboss.org/j2ee/dtd/jboss-ds_1_5.dtd">
+
+<datasources>
+
+ <local-tx-datasource>
+ <jndi-name>blogDatasource</jndi-name>
+ <connection-url>jdbc:mysql:///adam_blog?useUnicode=true&characterEncoding=UTF-8</connection-url>
+ <driver-class>com.mysql.jdbc.Driver</driver-class>
+ <user-name>blog</user-name>
+ <password>blog</password>
+<!--
+ <exception-sorter-class-name>
+ org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter
+ </exception-sorter-class-name>
+ <metadata>
+ <type-mapping>mySQL</type-mapping>
+ </metadata>
+-->
+ </local-tx-datasource>
+
+</datasources>
+
Added: feeds100P26/resources/components.properties
===================================================================
--- feeds100P26/resources/components.properties (rev 0)
+++ feeds100P26/resources/components.properties 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,2 @@
+jndiPattern \#{ejbName}/local
+debug true
Added: feeds100P26/resources/messages_en.properties
===================================================================
--- feeds100P26/resources/messages_en.properties (rev 0)
+++ feeds100P26/resources/messages_en.properties 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,173 @@
+up=\u2191
+down=\u2193
+left=\u2039
+right=\u203a
+
+validator.assertFalse=validation failed
+validator.assertTrue=validation failed
+validator.future=must be a future date
+validator.length=Length must be between {min} and {max}.
+validator.max=Must be less than or equal to {value}.
+validator.min=Must be greater than or equal to {value}.
+validator.notNull=may not be null
+validator.past=must be a past date
+validator.pattern=Must match "{regex}".
+validator.range=Must be between {min} and {max}.
+validator.size=Size must be between {min} and {max}.
+validator.email=Must be a well-formed email address.
+
+org.jboss.seam.loginFailed=Login failed.
+org.jboss.seam.loginSuccessful=Welcome, #0!
+
+org.jboss.seam.TransactionFailed=Transaction failed.
+org.jboss.seam.NoConversation=The conversation ended, timed out or was processing another request.
+org.jboss.seam.IllegalNavigation=Illegal navigation.
+org.jboss.seam.ProcessEnded=Process #0 already ended.
+org.jboss.seam.ProcessNotFound=Process #0 not found.
+org.jboss.seam.TaskEnded=Task #0 already ended.
+org.jboss.seam.TaskNotFound=Task #0 not found.
+org.jboss.seam.NotLoggedIn=Please log in first.
+
+javax.faces.component.UIInput.CONVERSION=value could not be converted to the expected type
+javax.faces.component.UIInput.REQUIRED=This field cannot be empty.
+javax.faces.component.UIInput.UPDATE=an error occurred when processing your submitted information
+javax.faces.component.UISelectOne.INVALID=value is not valid
+javax.faces.component.UISelectMany.INVALID=value is not valid
+
+javax.faces.converter.BigDecimalConverter.DECIMAL=value must be a number
+javax.faces.converter.BigDecimalConverter.DECIMAL_detail=value must be a signed decimal number consisting of zero or more digits, optionally followed by a decimal point and fraction, eg. {1}
+javax.faces.converter.BigIntegerConverter.BIGINTEGER=value must be an integer
+javax.faces.converter.BigIntegerConverter.BIGINTEGER_detail=value must be a signed integer number consisting of zero or more digits
+javax.faces.converter.BooleanConverter.BOOLEAN=value must be true or false
+javax.faces.converter.BooleanConverter.BOOLEAN_detail=value must be true or false (any value other than true will evaluate to false)
+javax.faces.converter.ByteConverter.BYTE=value must be a number between 0 and 255
+javax.faces.converter.ByteConverter.BYTE_detail=value must be a number between 0 and 255
+javax.faces.converter.CharacterConverter.CHARACTER=value must be a character
+javax.faces.converter.CharacterConverter.CHARACTER_detail=value must be a valid ASCII character
+javax.faces.converter.DateTimeConverter.DATE=value must be a date
+javax.faces.converter.DateTimeConverter.DATE_detail=value must be a date, eg. {1}
+javax.faces.converter.DateTimeConverter.TIME=value must be a time
+javax.faces.converter.DateTimeConverter.TIME_detail=value must be a time, eg. {1}
+javax.faces.converter.DateTimeConverter.DATETIME=value must be a date and time
+javax.faces.converter.DateTimeConverter.DATETIME_detail=value must be a date and time, eg. {1}
+javax.faces.converter.DateTimeConverter.PATTERN_TYPE=a pattern or type attribute must be specified to convert the value
+javax.faces.converter.DoubleConverter.DOUBLE=value must be a number
+javax.faces.converter.DoubleConverter.DOUBLE_detail=value must be a number between 4.9E-324 and 1.7976931348623157E308
+javax.faces.converter.EnumConverter.ENUM=value must be convertible to an enum
+javax.faces.converter.EnumConverter.ENUM_detail=value must be convertible to an enum or from the enum that contains the constant {1}
+javax.faces.converter.EnumConverter.ENUM_NO_CLASS=value must be convertible to an enum or from the enum, but no enum class provided
+javax.faces.converter.EnumConverter.ENUM_NO_CLASS_detail=value must be convertible to an enum or from the enum, but no enum class provided
+javax.faces.converter.FloatConverter.FLOAT=value must be a number
+javax.faces.converter.FloatConverter.FLOAT_detail=value must be a number between 1.4E-45 and 3.4028235E38
+javax.faces.converter.IntegerConverter.INTEGER=value must be an integer
+javax.faces.converter.IntegerConverter.INTEGER_detail=value must be an integer number between -2147483648 and 2147483647
+javax.faces.converter.LongConverter.LONG=value must be an integer
+javax.faces.converter.LongConverter.LONG_detail=must be an integer number between -9223372036854775808 and 9223372036854775807
+javax.faces.converter.NumberConverter.CURRENCY=value must be a currency amount
+javax.faces.converter.NumberConverter.CURRENCY_detail=value must be a currency amount, eg. {1}
+javax.faces.converter.NumberConverter.PERCENT=value must be a percentage amount
+javax.faces.converter.NumberConverter.PERCENT_detail=value must be a percentage amount, eg. {1}
+javax.faces.converter.NumberConverter.NUMBER=value must be a number
+javax.faces.converter.NumberConverter.NUMBER_detail=value must be a number
+javax.faces.converter.NumberConverter.PATTERN=value must be a number
+javax.faces.converter.NumberConverter.PATTERN_detail=value must be a number
+javax.faces.converter.ShortConverter.SHORT=value must be an integer
+javax.faces.converter.ShortConverter.SHORT_detail=value must be an integer number between -32768 and 32767
+
+javax.faces.validator.DoubleRangeValidator.MAXIMUM=value must be less than or equal to {0}
+javax.faces.validator.DoubleRangeValidator.MINIMUM=value must be greater than or equal to {0}
+javax.faces.validator.DoubleRangeValidator.NOT_IN_RANGE=value must be between {0} and {1}
+javax.faces.validator.DoubleRangeValidator.TYPE=value is not of the correct type
+javax.faces.validator.LengthValidator.MAXIMUM=value is must be shorter than or equal to {0} characters
+javax.faces.validator.LengthValidator.MINIMUM=value is must be longer than or equal to {0} characters
+javax.faces.validator.LongRangeValidator.MAXIMUM=value must be less than or equal to {0}
+javax.faces.validator.LongRangeValidator.MINIMUM=value must be greater than or equal to {0}
+javax.faces.validator.LongRangeValidator.NOT_IN_RANGE=value must be between {0} and {1}
+javax.faces.validator.LongRangeValidator.TYPE=value is not of the correct type
+
+javax.faces.validator.NOT_IN_RANGE=value must be between {0} and {1}
+javax.faces.converter.STRING=value could not be converted to a string
+
+blog.feed.deleted=Feed {0} deleted.
+blog.feed.updated=Feed {0} updated.
+blog.feed.added=Feed {0} added.
+blog.feed.accepted=Feed {0} accepted. Its posts will bead read and saved in a moment.
+blog.feed.proposed=Your feed: '{0}' has been added to our propositions queue. It will be now reviewed.
+
+blog.template.deleted=Template {0} of type {1} deleted.
+blog.template.updated=Template {0} of type {1} updated.
+blog.template.added=Template {0} of type {1} added.
+blog.template.new.existingname=A template with that name already exists.
+
+blog.feed.post.invalid=Post: '#0', property: #1, #2.
+blog.feed.enclosure.invalid=Enclosure on post: '#0' with url '#1', property: #2, #3
+blog.feed.image.invalid=Image for post: '#0', property: #1, #2
+
+blog.feed.remote.parseok.nocategories=Parsing the feed was successfull! However entries of this feed do \
+ not contain any category information - please check, if the feed contains only posts, that you'd like \
+ to include. If so, you can proceed.
+blog.feed.remote.parseok.categories=Parsing the feed was successfull! You can now (optionally) choose \
+ a category, from which posts you'd like to include, and proceed.
+blog.feed.remote.parsenotok=Parsing the feed failed, because of the following exception: #0.
+
+blog.feed.remote.updated=Remote feed {0} updated.
+blog.feed.remote.adding.quickstart=Enter your atom/rss2 feed address in the box to the left; if it is correct \
+ and the feed parses without any problems, you'll be able to proceed and fill in other details of the new feed.
+blog.feed.remote.mod.authors=You can choose how the author of a post is determined: the value can be either taken \
+ as it appears in the feed, can be always overwritten by the blog author (which is configurable later) or can be \
+ replaced by the blog author only when the post author is missing (default).
+
+blog.feed.individual.post.added=Post '{0}' added.
+blog.feed.individual.post.deleted=Post '{0}' deleted.
+
+blog.feed.aggregated.updated=Aggregated feed {0} changed.
+
+blog.feed.new.invalidname=Feed name may only contain small latin letters, numbers and _.
+blog.feed.new.existingname=A feed with that name already exists.
+
+blog.group.invalidname=Group name may only contain small latin letters, numbers and _.
+blog.group.existingname=A group with that name already exists.
+blog.group.deleted=Group '{0}' ({1}) deleted.
+blog.group.updated=Group '{0}' ({1}) updated.
+blog.group.added=Group '{0}' ({1}) added.
+blog.group.cannotdelete=Cannot delete group '{0}' ({1}), as there are still feeds assigned to it.
+
+blog.post.deleted=Post '{0}' deleted.
+
+blog.search.exception=Malformed search query: {0}.
+blog.search.emptyquery=Your query is empty.
+
+blog.configuration.saved=Configuration saved.
+blog.configuration.testmail.sent=Test e-mail sent.
+blog.configuration.testmail.notsent=Exception when sending a test e-mail: {0}.
+
+blog.feed.highlights.adding.info=A highlights feed lets you create a feed out of selected, arbitrary posts. \
+ After adding a new highlights feed, you'll be able to add posts to it by navigating to the post and clicking \
+ a link there. If you'd like to change the order in which the posts appear, or delete some, you'll just need to \
+ edit this feeds 'specific' properties.
+blog.feed.highlights.updated=Highlights feed '{0}' updated.
+blog.feed.highlights.post.added=Post '{0}' added to highlights feed '{1}'.
+
+blog.security.group.admin.added=Group {0} added to administrators.
+blog.security.group.admin.deleted=Group {0} deleted from administrators.
+
+blog.security.group.group.added=Group {0} added to administrators of group {1}.
+blog.security.group.group.deleted=Group {0} deleted from administrators of group {1}.
+
+blog.security.group.feed.added=Group {0} added to administrators of feed {1}.
+blog.security.group.feed.deleted=Group {0} deleted from administrators of feed {1}.
+
+blog.security.user.admin.added=User {0} added to administrators.
+blog.security.user.admin.deleted=User {0} deleted from administrators.
+
+blog.security.user.group.added=User {0} added to administrators of group {1}.
+blog.security.user.group.deleted=User {0} deleted from administrators of group {1}.
+
+blog.security.user.feed.added=User {0} added to administrators of feed {1}.
+blog.security.user.feed.deleted=User {0} deleted from administrators of feed {1}.
+
+blog.security.user.feedview.added=User {0} added to viewers of feed {1}.
+blog.security.user.feedview.deleted=User {0} deleted from viewers of feed {1}.
+
+blog.security.group.feedview.added=Group {0} added to viewers of feed {1}.
+blog.security.group.feedview.deleted=Group {0} deleted from viewers of feed {1}.
\ No newline at end of file
Added: feeds100P26/resources/seam.properties
===================================================================
Added: feeds100P26/resources/templates/atom_standard.vm
===================================================================
--- feeds100P26/resources/templates/atom_standard.vm (rev 0)
+++ feeds100P26/resources/templates/atom_standard.vm 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd">
+<id>$tools.feedLink($feed, $xmlType)</id>
+<title type="html"><![CDATA[$feed.title]]></title>
+<updated>$tools.formatDate($tools.feedPubDate($feed, $posts))</updated>
+<author>
+ <name>$feed.author</name>
+</author>
+<link rel="alternate" type="text/html" href="$tools.feedPageLink($feed)"/>
+<link rel="self" type="application/atom+xml" href="$tools.feedLink($feed, $xmlType)"/>
+
+#foreach($post in $posts)
+<entry>
+ <id>$tools.postLink($post)</id>
+ <title type="html"><![CDATA[$post.title]]></title>
+ <link rel="alternate" type="text/html" href="$tools.postLink($post)"/>
+
+ <updated>$tools.formatDate($post.modified)</updated>
+ <published>$tools.formatDate($post.published)</published>
+
+ <content type="html" xml:lang="en">
+ <![CDATA[$post.content
+
+ #if($feed.showDelicious or $feed.showDzone or $feed.showDigg)
+ <p>
+ #if($feed.showDzone)
+ <a href="http://www.dzone.com/links/add.html?url=$postToTools.encodeLinkForDelicious($post)&title=$postToTools.encodeTitleForDelicious($post)">
+ Post to DZone</a>  
+ #end
+ #if($feed.showDelicious)
+ <a href="http://del.icio.us/post?v=4&url=$postToTools.encodeLinkForDelicious($post)&title=$postToTools.encodeTitleForDelicious($post)">
+ Post to del.icio.us</a>  
+ #end
+ #if($feed.showDigg)
+ <a href="http://digg.com/submit?url=$postToTools.encodeLinkForDigg($post)&title=$postToTools.encodeTitleForDigg($post)&bodytext=$postToTools.encodeBodyForDigg($post)&media=news&topic=programming">
+ Digg this!</a>  
+ #end
+ </p>
+ #end
+ ]]>
+ </content>
+
+ <author>
+ <name>$post.effectiveAuthor</name>
+ </author>
+
+ #foreach($enclosure in $post.enclosures)
+ <link href="$enclosure.url" rel="enclosure" length="$enclosure.length" type="$enclosure.type" />
+ #end
+
+ #foreach($image in $post.images)
+ <itunes:image href="$image.url" />
+ #end
+</entry>
+#end
+</feed>
Added: feeds100P26/resources/templates/rss1_standard.vm
===================================================================
--- feeds100P26/resources/templates/rss1_standard.vm (rev 0)
+++ feeds100P26/resources/templates/rss1_standard.vm 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+
+<rdf:RDF
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns="http://purl.org/rss/1.0/"
+>
+ <channel>
+ <title>$feed.title</title>
+ <link>$tools.feedPageLink($feed)</link>
+
+ <items>
+ <rdf:Seq>
+ #foreach($post in $posts)
+ <rdf:li resource="$tools.postLink($post)" />
+ #end
+ </rdf:Seq>
+ </items>
+ </channel>
+
+ #foreach($post in $posts)
+ <item rdf:about="$tools.postLink($post)">
+ <title><![CDATA[$post.title]]></title>
+ <link>$tools.postLink($post)</link>
+ <description><![CDATA[$post.content]]></description>
+ </item>
+ #end
+</rdf:RDF>
\ No newline at end of file
Added: feeds100P26/resources/templates/rss2_standard.vm
===================================================================
--- feeds100P26/resources/templates/rss2_standard.vm (rev 0)
+++ feeds100P26/resources/templates/rss2_standard.vm 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<rss version="2.0"
+ xmlns:content="http://purl.org/rss/1.0/modules/content/"
+ xmlns:wfw="http://wellformedweb.org/CommentAPI/"
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <channel>
+ <title>$feed.title</title>
+ <link>$tools.feedPageLink($feed)</link>
+ <language>en</language>
+ <docs>http://blogs.law.harvard.edu/tech/rss</docs>
+ <generator>JBoss Feeds</generator>
+ <managingEditor>$feed.author</managingEditor>
+ <pubDate>$tools.formatDate($tools.feedPubDate($feed, $posts))</pubDate>
+
+ #foreach($post in $posts)
+ <item>
+ <title><![CDATA[$post.title]]></title>
+ <link>$tools.postLink($post)</link>
+ <description><![CDATA[$post.content]]></description>
+ <guid>$tools.postLink($post)</guid>
+ <pubDate>$tools.formatDate($post.published)</pubDate>
+ <dc:creator>$post.effectiveAuthor</dc:creator>
+ </item>
+ #end
+
+ </channel>
+</rss>
\ No newline at end of file
Added: feeds100P26/resources/velocity.properties
===================================================================
--- feeds100P26/resources/velocity.properties (rev 0)
+++ feeds100P26/resources/velocity.properties 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,9 @@
+input.encoding = UTF-8
+output.encoding = UTF-8
+
+resource.loader = database
+
+database.resource.loader.description = Velocity File Resource Loader
+database.resource.loader.class = org.jboss.blog.session.xml.velocity.DatabaseResourceLoader
+database.resource.loader.cache = false
+database.resource.loader.modificationCheckInterval = 2
\ No newline at end of file
Added: feeds100P26/resources-portlet/WEB-INF/blog-object.xml
===================================================================
--- feeds100P26/resources-portlet/WEB-INF/blog-object.xml (rev 0)
+++ feeds100P26/resources-portlet/WEB-INF/blog-object.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE deployments PUBLIC
+ "-//JBoss Portal//DTD Portal Object 2.6//EN"
+ "http://www.jboss.org/portal/dtd/portal-object_2_6.dtd">
+<deployments>
+ <deployment>
+ <parent-ref>default.default</parent-ref>
+ <if-exists>overwrite</if-exists>
+ <window>
+ <window-name>DefaultBlogPortletWindow</window-name>
+ <instance-ref>
+ DefaultBlogPortletInstance
+ </instance-ref>
+ <region>right</region>
+ <height>3</height>
+ </window>
+ </deployment>
+ <deployment>
+ <parent-ref>default.communityhome</parent-ref>
+ <if-exists>overwrite</if-exists>
+ <window>
+ <window-name>CommunityBlogPortletWindow</window-name>
+ <instance-ref>
+ CommunityBlogPortletInstance
+ </instance-ref>
+ <region>right1_6</region>
+ <height>1</height>
+ </window>
+ </deployment>
+</deployments>
Added: feeds100P26/resources-portlet/WEB-INF/jboss-app.xml
===================================================================
--- feeds100P26/resources-portlet/WEB-INF/jboss-app.xml (rev 0)
+++ feeds100P26/resources-portlet/WEB-INF/jboss-app.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,3 @@
+<jboss-app>
+ <app-name>feeds</app-name>
+</jboss-app>
\ No newline at end of file
Added: feeds100P26/resources-portlet/WEB-INF/jboss-portlet.xml
===================================================================
--- feeds100P26/resources-portlet/WEB-INF/jboss-portlet.xml (rev 0)
+++ feeds100P26/resources-portlet/WEB-INF/jboss-portlet.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<!DOCTYPE portlet-app PUBLIC
+ "-//JBoss Portal//DTD JBoss Portlet 2.6//EN"
+ "http://www.jboss.org/portal/dtd/jboss-portlet_2_6.dtd">
+<portlet-app>
+ <portlet>
+ <portlet-name>BlogPortlet</portlet-name>
+ </portlet>
+</portlet-app>
\ No newline at end of file
Added: feeds100P26/resources-portlet/WEB-INF/portlet-instances.xml
===================================================================
--- feeds100P26/resources-portlet/WEB-INF/portlet-instances.xml (rev 0)
+++ feeds100P26/resources-portlet/WEB-INF/portlet-instances.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE deployments PUBLIC
+ "-//JBoss Portal//DTD Portlet Instances 2.6//EN"
+ "http://www.jboss.org/portal/dtd/portlet-instances_2_6.dtd">
+<deployments>
+ <deployment>
+ <if-exists>overwrite</if-exists>
+ <instance>
+ <instance-id>DefaultBlogPortletInstance</instance-id>
+ <portlet-ref>BlogPortlet</portlet-ref>
+ <preferences>
+ <preference>
+ <name>feedName</name>
+ <value>all</value>
+ </preference>
+ <preference>
+ <name>numberOfPosts</name>
+ <value>3</value>
+ </preference>
+ <preference>
+ <name>summaryLength</name>
+ <value>0</value>
+ </preference>
+ <preference>
+ <name>showDate</name>
+ <value>true</value>
+ </preference>
+ <preference>
+ <name>jsp</name>
+ <value>/view_main.jsp</value>
+ </preference>
+ </preferences>
+ </instance>
+ </deployment>
+ <deployment>
+ <if-exists>overwrite</if-exists>
+ <instance>
+ <instance-id>CommunityBlogPortletInstance</instance-id>
+ <portlet-ref>BlogPortlet</portlet-ref>
+ <preferences>
+ <preference>
+ <name>feedName</name>
+ <value>communityhome</value>
+ </preference>
+ <preference>
+ <name>numberOfPosts</name>
+ <value>10</value>
+ </preference>
+ <preference>
+ <name>summaryLength</name>
+ <value>0</value>
+ </preference>
+ <preference>
+ <name>showDate</name>
+ <value>false</value>
+ </preference>
+ <preference>
+ <name>jsp</name>
+ <value>/view.jsp</value>
+ </preference>
+ </preferences>
+ </instance>
+ </deployment>
+</deployments>
Added: feeds100P26/resources-portlet/WEB-INF/portlet.xml
===================================================================
--- feeds100P26/resources-portlet/WEB-INF/portlet.xml (rev 0)
+++ feeds100P26/resources-portlet/WEB-INF/portlet.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd
+ http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
+ version="1.0">
+ <portlet>
+ <portlet-name>BlogPortlet</portlet-name>
+ <portlet-class>org.jboss.blog.portlet.BlogPortlet</portlet-class>
+ <supports>
+ <mime-type>text/html</mime-type>
+ <portlet-mode>VIEW</portlet-mode>
+ </supports>
+ <supported-locale>en</supported-locale>
+ <expiration-cache>60</expiration-cache>
+ <portlet-info>
+ <title>JBoss Blog Portlet</title>
+ </portlet-info>
+ <portlet-preferences>
+ <preference>
+ <name>feedName</name>
+ </preference>
+ <preference>
+ <name>numberOfPosts</name>
+ <value>5</value>
+ </preference>
+ <preference>
+ <name>summaryLength</name>
+ <value>200</value>
+ </preference>
+ <preference>
+ <name>showDate</name>
+ <value>true</value>
+ </preference>
+ <preference>
+ <name>jsp</name>
+ <value>/view.jsp</value>
+ </preference>
+ </portlet-preferences>
+ </portlet>
+</portlet-app>
+
Added: feeds100P26/resources-portlet/WEB-INF/web.xml
===================================================================
--- feeds100P26/resources-portlet/WEB-INF/web.xml (rev 0)
+++ feeds100P26/resources-portlet/WEB-INF/web.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+ version="2.5">
+ <filter>
+ <filter-name>Resources Filter</filter-name>
+ <filter-class>org.jboss.shotoku.web.ShotokuResourcesFilter</filter-class>
+ </filter>
+
+ <filter-mapping>
+ <filter-name>Resources Filter</filter-name>
+ <url-pattern>/*</url-pattern>
+ <dispatcher>ERROR</dispatcher>
+ <dispatcher>FORWARD</dispatcher>
+ <dispatcher>INCLUDE</dispatcher>
+ <dispatcher>REQUEST</dispatcher>
+ </filter-mapping>
+</web-app>
Added: feeds100P26/src/action/org/jboss/blog/servlet/FeedsServlet.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/servlet/FeedsServlet.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/servlet/FeedsServlet.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,80 @@
+package org.jboss.blog.servlet;
+
+import org.jboss.blog.service.FeedNotFoundException;
+import org.jboss.blog.session.xml.velocity.InvalidTemplateTypeException;
+import org.jboss.blog.session.xml.XmlService;
+import org.jboss.blog.session.xml.content.ContentResponse;
+import org.jboss.blog.session.xml.content.ServletResponseContentResponse;
+import org.jboss.seam.Component;
+import org.jboss.seam.log.Logging;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.transaction.Status;
+import javax.transaction.SystemException;
+import javax.transaction.UserTransaction;
+import java.io.IOException;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class FeedsServlet extends HttpServlet {
+ private void writeErrorMessage(String message, HttpServletResponse response) throws IOException {
+ response.setContentType("text/html");
+ response.getWriter().println(message);
+ response.getWriter().flush();
+ }
+
+ private void rollbackTx(UserTransaction tx, boolean txStarted) {
+ try {
+ if (txStarted) {
+ tx.rollback();
+ }
+ } catch (SystemException e1) {
+ Logging.getLog(FeedsServlet.class).error("Exception when rolling back the transaction", e1);
+ }
+ }
+
+ protected void service(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String feedType = request.getParameter("type");
+ String feedName = request.getParameter("name");
+ String feedKey = request.getParameter("key");
+
+ UserTransaction tx = null;
+ boolean txStarted = false;
+ try {
+ tx = (UserTransaction) Component.getInstance("org.jboss.seam.transaction.transaction");
+ if (tx.getStatus() != Status.STATUS_ACTIVE) {
+ txStarted = true;
+ tx.begin();
+ }
+
+ // TODO: expires, created, if-not-modified-since
+
+ ContentResponse contentResponse = new ServletResponseContentResponse(response);
+
+ XmlService xmlService = (XmlService) Component.getInstance("xmlService");
+ xmlService.writeXml(feedType, feedName, feedKey, contentResponse);
+ response.getWriter().flush();
+
+ if (txStarted) {
+ tx.commit();
+ }
+ } catch (InvalidTemplateTypeException e) {
+ rollbackTx(tx, txStarted);
+
+ writeErrorMessage("The given feed type does not exist.", response);
+ } catch (FeedNotFoundException e) {
+ rollbackTx(tx, txStarted);
+
+ writeErrorMessage("Requested feed not found.", response);
+ } catch (Exception e) {
+ rollbackTx(tx, txStarted);
+
+ throw new ServletException(e);
+ }
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/cache/CacheManager.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/cache/CacheManager.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/cache/CacheManager.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,22 @@
+package org.jboss.blog.session.cache;
+
+import org.jboss.blog.model.feed.RestrictedFeed;
+import org.jboss.blog.model.RestrictedPost;
+import org.jboss.blog.session.xml.content.InMemoryContentResponse;
+
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public interface CacheManager {
+ void evictAll();
+
+ void putFeedPosts(RestrictedFeed feed, List<? extends RestrictedPost> posts, int from, int to);
+
+ List<? extends RestrictedPost> getFeedPosts(String feedName, int from, int to);
+
+ void putFeedXml(String feedName, String feedType, InMemoryContentResponse xml);
+
+ InMemoryContentResponse getFeedXml(String feedName, String feedType);
+}
Added: feeds100P26/src/action/org/jboss/blog/session/cache/CacheManagerHashMapImpl.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/cache/CacheManagerHashMapImpl.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/cache/CacheManagerHashMapImpl.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,131 @@
+package org.jboss.blog.session.cache;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Logger;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.log.Log;
+import org.jboss.seam.ScopeType;
+import org.jboss.blog.model.feed.RestrictedFeed;
+import org.jboss.blog.model.RestrictedPost;
+import org.jboss.blog.model.RestrictedImage;
+import org.jboss.blog.model.RestrictedCategory;
+import org.jboss.blog.model.RestrictedEnclosure;
+import org.jboss.blog.session.xml.content.InMemoryContentResponse;
+
+import javax.annotation.PostConstruct;
+import java.lang.ref.SoftReference;
+import java.util.List;
+import java.util.Map;
+import java.util.ArrayList;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * TODO: check Soft References
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("cacheManager")
+ at Scope(ScopeType.APPLICATION)
+ at AutoCreate
+public class CacheManagerHashMapImpl implements CacheManager {
+ @Logger
+ private Log log;
+
+ private Map<Object, Object> cache;
+
+ @PostConstruct
+ public void init() {
+ cache = new ConcurrentHashMap<Object, Object>();
+ }
+
+ //
+
+ private <T> T getFromSoftReference(SoftReference<T> reference) {
+ if (reference == null) {
+ return null;
+ }
+
+ return reference.get();
+ }
+
+ private void readPost(RestrictedPost post) {
+ post.getFeed().getId();
+
+ for (RestrictedCategory category : post.getCategories()) {
+ category.getId();
+ }
+
+ for (RestrictedEnclosure enclosure : post.getEnclosures()) {
+ enclosure.getId();
+ }
+
+ for (RestrictedImage image : post.getImages()) {
+ image.getId();
+ }
+ }
+
+ private void readPosts(List<? extends RestrictedPost> posts) {
+ for (RestrictedPost post : posts) {
+ readPost(post);
+ }
+ }
+
+ //
+
+ public void evictAll() {
+ log.debug("Evicting everything from the cache.");
+ cache.clear();
+ }
+
+ //
+
+ private String getFeedPostsFqn(String feedName, int from, int to) {
+ return feedName + "/" + from + "/" + to;
+ }
+
+ private <T> List<T> copyList(List<T> original) {
+ return new ArrayList<T>(original);
+ }
+
+ public void putFeedPosts(RestrictedFeed feed, List<? extends RestrictedPost> posts, int from, int to) {
+ readPosts(posts);
+
+ log.debug("Putting feed '#0' posts into the cache, from #1 to #2.", feed.getName(), from, to);
+
+ cache.put(getFeedPostsFqn(feed.getName(), from, to), new SoftReference<List<? extends RestrictedPost>>(
+ copyList(posts)));
+ }
+
+ public List<? extends RestrictedPost> getFeedPosts(String feedName, int from, int to) {
+ //noinspection unchecked
+ List<? extends RestrictedPost> inCache =
+ getFromSoftReference(((SoftReference<List<? extends RestrictedPost>>) cache.get(
+ getFeedPostsFqn(feedName, from, to))));
+ log.debug("Getting feed '#0' posts from the cache, from #1 to #2, result: #3.",
+ feedName, from, to, inCache);
+ return inCache == null ? null : copyList(inCache);
+ }
+
+ //
+
+ private final static String FEED_XML = "$feedxml";
+
+ private String getFeedXmlFqn(String feedName, String feedType) {
+ return FEED_XML + "/" + feedName + "/" + (feedType == null ? null : feedType.toLowerCase());
+ }
+
+ public void putFeedXml(String feedName, String feedType, InMemoryContentResponse xml) {
+ log.debug("Putting xml for feed '#0' to the cache, type: #1.", feedName, feedType);
+ cache.put(getFeedXmlFqn(feedName, feedType),
+ new SoftReference<InMemoryContentResponse>(xml));
+ }
+
+ public InMemoryContentResponse getFeedXml(String feedName, String feedType) {
+ //noinspection unchecked
+ InMemoryContentResponse inCache = getFromSoftReference(((SoftReference<InMemoryContentResponse>)
+ cache.get(getFeedXmlFqn(feedName, feedType))));
+ log.debug("Getting xml for feed '#0' from the cache, type: #1, result: #2.",
+ feedName, feedType, inCache);
+ return inCache;
+ }
+}
\ No newline at end of file
Added: feeds100P26/src/action/org/jboss/blog/session/cache/FeedsChangesObserver.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/cache/FeedsChangesObserver.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/cache/FeedsChangesObserver.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,47 @@
+package org.jboss.blog.session.cache;
+
+import org.jboss.seam.annotations.Observer;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.In;
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.Post;
+import org.jboss.blog.model.Template;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("feedsChangesObserver")
+public class FeedsChangesObserver {
+ @In
+ private CacheManager cacheManager;
+
+ @Observer({"org.jboss.blog.feed.updated", "org.jboss.blog.feed.deleted"})
+ public void feedUpdated(Feed feed) {
+ cacheManager.evictAll();
+ }
+
+ @Observer({"org.jboss.blog.feed.added"})
+ public void feedAdded(Feed feed) {
+ cacheManager.evictAll();
+ }
+
+ @Observer({"org.jboss.blog.post.updated", "org.jboss.blog.post.deleted"})
+ public void postUpdated(Post post) {
+ cacheManager.evictAll();
+ }
+
+ @Observer("org.jboss.blog.post.added")
+ public void postAdded(Post post) {
+ cacheManager.evictAll();
+ }
+
+ @Observer({"org.jboss.blog.template.updated", "org.jboss.blog.template.deleted"})
+ public void templateUpdated(Template template) {
+ cacheManager.evictAll();
+ }
+
+ @Observer("org.jboss.blog.template.added")
+ public void templateAdded(Template template) {
+ cacheManager.evictAll();
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/category/CategoryServiceBean.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/category/CategoryServiceBean.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/category/CategoryServiceBean.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,35 @@
+package org.jboss.blog.session.category;
+
+import org.jboss.blog.model.Category;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+
+import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Scope(ScopeType.STATELESS)
+ at Name("categoryService")
+ at AutoCreate
+public class CategoryServiceBean {
+ @In
+ private EntityManager entityManager;
+
+ public Category getCategory(String name) {
+ try {
+ return (Category) entityManager.createQuery("select cat from Category cat where cat.name = ?1")
+ .setParameter(1, name).getSingleResult();
+ } catch (NoResultException e) {
+ Category ret = new Category(name);
+ entityManager.persist(ret);
+ entityManager.flush();
+
+ return ret;
+ }
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/configuration/ConfigurationManager.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/configuration/ConfigurationManager.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/configuration/ConfigurationManager.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,76 @@
+package org.jboss.blog.session.configuration;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.security.Restrict;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.faces.FacesMessages;
+import org.jboss.seam.faces.Renderer;
+import org.jboss.blog.model.configuration.Configuration;
+import org.jboss.blog.tools.GeneralTools;
+
+import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
+import javax.persistence.NonUniqueResultException;
+import javax.faces.application.FacesMessage;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("configurationManager")
+ at Scope(ScopeType.APPLICATION)
+ at AutoCreate
+public class ConfigurationManager {
+ @In
+ private EntityManager entityManager;
+
+ @In
+ private FacesMessages facesMessages;
+
+ @In(create = true)
+ private Renderer renderer;
+
+ private Configuration initNewConfiguration() {
+ Configuration conf = new Configuration();
+ conf.setConnectionTimeout(10000);
+ conf.setReadTimeout(6000);
+ conf.setUpdateInterval(900);
+
+ return conf;
+ }
+
+ public synchronized Configuration getConfiguration() {
+ try {
+ return (Configuration) entityManager.createQuery("select conf from Configuration conf").getSingleResult();
+ } catch (NoResultException e) {
+ Configuration conf = initNewConfiguration();
+ entityManager.persist(conf);
+ entityManager.flush();
+
+ return conf;
+ } catch (NonUniqueResultException e) {
+ throw new RuntimeException("There should be at most 1 configuration entity!", e);
+ }
+ }
+
+ @Restrict("#{identity.hasPermission('admin', null)}")
+ public void save() {
+ entityManager.flush();
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, "blog.configuration.saved");
+ }
+
+ @Restrict("#{identity.hasPermission('admin', null)}")
+ public void testEmail() {
+ save();
+
+ try {
+ renderer.render("/emails/test_email.xhtml");
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, "blog.configuration.testmail.sent");
+ } catch (Exception e) {
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_ERROR, "blog.configuration.testmail.notsent",
+ GeneralTools.getExceptionStackTrace(e));
+ }
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/converter/FeedConverter.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/converter/FeedConverter.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/converter/FeedConverter.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,37 @@
+package org.jboss.blog.session.converter;
+
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.service.FeedsService;
+import org.jboss.blog.service.FeedNotFoundException;
+import org.jboss.blog.session.exceptions.FeedNotFoundRuntimeException;
+import org.jboss.seam.Component;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Transactional;
+import org.jboss.seam.annotations.faces.Converter;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("feedConverter")
+ at BypassInterceptors
+ at Converter
+public class FeedConverter implements javax.faces.convert.Converter {
+ @Transactional
+ public Object getAsObject(FacesContext context, UIComponent cmp, String value) {
+ FeedsService feedsService = (FeedsService) Component.getInstance("feedsService");
+
+ try {
+ return feedsService.getFeed(value);
+ } catch (FeedNotFoundException e) {
+ throw new FeedNotFoundRuntimeException(e.getMessage());
+ }
+ }
+
+ public String getAsString(FacesContext context, UIComponent cmp, Object value) {
+ return value == null ? null : ((Feed) value).getName();
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/converter/GroupConverter.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/converter/GroupConverter.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/converter/GroupConverter.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,41 @@
+package org.jboss.blog.session.converter;
+
+import org.jboss.blog.model.Group;
+import org.jboss.seam.Component;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Transactional;
+import org.jboss.seam.annotations.faces.Converter;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.persistence.EntityManager;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("groupConverter")
+ at BypassInterceptors
+ at Converter
+public class GroupConverter implements javax.faces.convert.Converter {
+ @Transactional
+ public Object getAsObject(FacesContext context, UIComponent cmp, String value) {
+ EntityManager entityManager = (EntityManager) Component.getInstance("entityManager");
+
+ entityManager.joinTransaction();
+
+ Integer id;
+ id = Integer.parseInt(value);
+
+ return entityManager.find(Group.class, id);
+ }
+
+ public String getAsString(FacesContext context, UIComponent cmp, Object value) {
+ if (value == null) {
+ return null;
+ }
+
+ Integer id = ((Group) value).getId();
+ return id == null ? null : id.toString();
+ }
+}
\ No newline at end of file
Added: feeds100P26/src/action/org/jboss/blog/session/converter/PostConverter.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/converter/PostConverter.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/converter/PostConverter.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,38 @@
+package org.jboss.blog.session.converter;
+
+import org.jboss.blog.model.Post;
+import org.jboss.blog.service.FeedsService;
+import org.jboss.blog.service.PostNotFoundException;
+import org.jboss.blog.session.exceptions.PostNotFoundRuntimeException;
+import org.jboss.seam.Component;
+import org.jboss.seam.log.Log;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Transactional;
+import org.jboss.seam.annotations.faces.Converter;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("postConverter")
+ at BypassInterceptors
+ at Converter
+public class PostConverter implements javax.faces.convert.Converter {
+ @Transactional
+ public Object getAsObject(FacesContext context, UIComponent cmp, String value) {
+ FeedsService feedsService = (FeedsService) Component.getInstance("feedsService");
+
+ try {
+ return feedsService.getPost(value);
+ } catch (PostNotFoundException e) {
+ throw new PostNotFoundRuntimeException(e.getMessage());
+ }
+ }
+
+ public String getAsString(FacesContext context, UIComponent cmp, Object value) {
+ return value == null ? null : ((Post) value).getTitleAsId();
+ }
+}
\ No newline at end of file
Added: feeds100P26/src/action/org/jboss/blog/session/converter/TemplateConverter.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/converter/TemplateConverter.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/converter/TemplateConverter.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,41 @@
+package org.jboss.blog.session.converter;
+
+import org.jboss.blog.model.Template;
+import org.jboss.seam.Component;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Transactional;
+import org.jboss.seam.annotations.faces.Converter;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.persistence.EntityManager;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("templateConverter")
+ at BypassInterceptors
+ at Converter
+public class TemplateConverter implements javax.faces.convert.Converter {
+ @Transactional
+ public Object getAsObject(FacesContext context, UIComponent cmp, String value) {
+ EntityManager entityManager = (EntityManager) Component.getInstance("entityManager");
+
+ entityManager.joinTransaction();
+
+ Integer id;
+ id = Integer.parseInt(value);
+
+ return entityManager.find(Template.class, id);
+ }
+
+ public String getAsString(FacesContext context, UIComponent cmp, Object value) {
+ if (value == null) {
+ return null;
+ }
+
+ Integer id = ((Template) value).getId();
+ return id == null ? null : id.toString();
+ }
+}
\ No newline at end of file
Added: feeds100P26/src/action/org/jboss/blog/session/exceptions/FeedNotFoundRuntimeException.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/exceptions/FeedNotFoundRuntimeException.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/exceptions/FeedNotFoundRuntimeException.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,21 @@
+package org.jboss.blog.session.exceptions;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class FeedNotFoundRuntimeException extends RuntimeException {
+ public FeedNotFoundRuntimeException() {
+ }
+
+ public FeedNotFoundRuntimeException(String message) {
+ super(message);
+ }
+
+ public FeedNotFoundRuntimeException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public FeedNotFoundRuntimeException(Throwable cause) {
+ super(cause);
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/exceptions/PostNotFoundRuntimeException.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/exceptions/PostNotFoundRuntimeException.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/exceptions/PostNotFoundRuntimeException.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,21 @@
+package org.jboss.blog.session.exceptions;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class PostNotFoundRuntimeException extends RuntimeException {
+ public PostNotFoundRuntimeException() {
+ }
+
+ public PostNotFoundRuntimeException(String message) {
+ super(message);
+ }
+
+ public PostNotFoundRuntimeException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public PostNotFoundRuntimeException(Throwable cause) {
+ super(cause);
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/feed/FeedsServiceImpl.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/feed/FeedsServiceImpl.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/feed/FeedsServiceImpl.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,140 @@
+package org.jboss.blog.session.feed;
+
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.feed.RestrictedFeed;
+import org.jboss.blog.model.Post;
+import org.jboss.blog.model.RestrictedPost;
+import org.jboss.blog.service.FeedNotFoundException;
+import org.jboss.blog.service.FeedsService;
+import org.jboss.blog.service.PostNotFoundException;
+import org.jboss.blog.session.feed.type.FeedTypes;
+import org.jboss.blog.session.feed.posts.DatabaseFeedPosts;
+import org.jboss.blog.session.cache.CacheManager;
+import org.jboss.blog.session.security.tools.FeedSecurityTools;
+import org.jboss.blog.session.security.FeedsIdentity;
+import org.jboss.seam.annotations.*;
+import org.jboss.seam.log.Log;
+import org.jboss.seam.ScopeType;
+
+import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("feedsService")
+ at Scope(ScopeType.STATELESS)
+ at AutoCreate
+public class FeedsServiceImpl implements FeedsService {
+ @In
+ private EntityManager entityManager;
+
+ @In
+ private FeedTypes feedTypes;
+
+ @In
+ private DatabaseFeedPosts databaseFeedPosts;
+
+ @In
+ private CacheManager cacheManager;
+
+ @In
+ private FeedsIdentity identity;
+
+ @Logger
+ private Log log;
+
+ public Post getPost(String titleAsId) throws PostNotFoundException {
+ log.debug("Reading post '#0' from the DB.", titleAsId);
+
+ if (titleAsId == null) {
+ throw new PostNotFoundException(titleAsId);
+ }
+
+ try {
+ return (Post) entityManager.createQuery("select post from Post post where post.titleAsId = ?1")
+ .setParameter(1, titleAsId).setHint("org.hibernate.cacheable", Boolean.TRUE).getSingleResult();
+ } catch (NoResultException e) {
+ throw new PostNotFoundException(titleAsId);
+ }
+ }
+
+ public Feed getFeed(String feedName) throws FeedNotFoundException {
+ log.debug("Reading feed '#0' from the DB.", feedName);
+
+ if (feedName == null) {
+ throw new FeedNotFoundException(feedName);
+ }
+
+ try {
+ return (Feed) entityManager.createQuery("select feed from Feed feed where feed.name = ?1")
+ .setParameter(1, feedName).setHint("org.hibernate.cacheable", Boolean.TRUE).getSingleResult();
+ } catch (NoResultException e) {
+ throw new FeedNotFoundException(feedName);
+ }
+ }
+
+ public List<? extends RestrictedPost> getPosts(RestrictedFeed feed, int from, int to) {
+ boolean restricted = false;
+
+ // We want to get restricted feeds, if we are logged in, the current feed is restricted and
+ // we have sufficient permissions to view the feed.
+ if (identity.isLoggedIn() && feed.isFeedRestricted() && FeedSecurityTools.canViewFeed(feed, true)) {
+ restricted = true;
+ }
+
+ return getPosts(feed, from, to, restricted);
+ }
+
+ public List<? extends RestrictedPost> getPosts(RestrictedFeed feed, int from, int to, boolean restricted) {
+ boolean isFeedRestricted = feed.isFeedRestricted();
+
+ // If the feed isn't restricted, then we set the flag not to include restricted posts.
+ if (!isFeedRestricted) {
+ restricted = false;
+ }
+
+ // We return an empty list if:
+ // - we don't want restricted posts, but this feed is restricted
+ // - we want restricted posts, this feed is restricted, but we can't view it.
+ if ((!restricted && isFeedRestricted) || (restricted && isFeedRestricted &&
+ !FeedSecurityTools.canViewFeed(feed, restricted))) {
+ log.debug("Reading restricted feed '#0', returning an empty list.", feed.getName());
+ return new ArrayList<RestrictedPost>();
+ }
+
+ // We use the cache only if the feed isn't restricted.
+ if (!isFeedRestricted) {
+ List<? extends RestrictedPost> inCache = cacheManager.getFeedPosts(feed.getName(), from, to);
+
+ if (inCache != null) {
+ return inCache;
+ }
+ }
+
+ List<? extends RestrictedPost> posts;
+
+ try {
+ log.debug("Reading feed '#0' posts from the DB, from #1 to #2, restricted = #3.", feed.getName(), from, to,
+ restricted);
+ posts = feedTypes.getFeedDao(feed).getPosts(from, to, restricted);
+ } catch (InvalidFeedTypeException e) {
+ log.error(e);
+ return new ArrayList<RestrictedPost>();
+ }
+
+ if (posts != null && !isFeedRestricted) {
+ cacheManager.putFeedPosts(feed, posts, from, to);
+ }
+
+ return posts;
+ }
+
+ public List<? extends RestrictedPost> getPosts(int from, int to) {
+ log.debug("Reading posts from the DB, from #0 to #1.", from, to);
+
+ return databaseFeedPosts.getPosts(from, to);
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/feed/InvalidFeedTypeException.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/feed/InvalidFeedTypeException.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/feed/InvalidFeedTypeException.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,21 @@
+package org.jboss.blog.session.feed;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class InvalidFeedTypeException extends Exception {
+ public InvalidFeedTypeException() {
+ }
+
+ public InvalidFeedTypeException(String message) {
+ super(message);
+ }
+
+ public InvalidFeedTypeException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public InvalidFeedTypeException(Throwable cause) {
+ super(cause);
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/feed/dao/AggregatedFeedDao.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/feed/dao/AggregatedFeedDao.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/feed/dao/AggregatedFeedDao.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,34 @@
+package org.jboss.blog.session.feed.dao;
+
+import org.jboss.blog.model.feed.AggregatedFeed;
+import org.jboss.blog.model.RestrictedPost;
+import org.jboss.blog.session.feed.posts.AggregatedFeedPosts;
+import org.jboss.blog.session.feed.type.FeedType;
+import org.jboss.seam.Component;
+
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at FeedType(
+ name = "aggregated",
+ addPage = "/manage/aggregated/aggregated_add.xhtml",
+ editPage = "/manage/aggregated/aggregated_edit.xhtml",
+ model = AggregatedFeed.class)
+public class AggregatedFeedDao implements FeedDao {
+ private AggregatedFeed aggregatedFeed;
+
+ public AggregatedFeedDao(AggregatedFeed aggregatedFeed) {
+ this.aggregatedFeed = aggregatedFeed;
+ }
+
+ public List<? extends RestrictedPost> getPosts(int from, int to, boolean restricted) {
+ return ((AggregatedFeedPosts) Component.getInstance("aggregatedFeedPosts")).getPosts(
+ aggregatedFeed, from, to, restricted);
+ }
+
+ public void update() {
+
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/feed/dao/FeedDao.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/feed/dao/FeedDao.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/feed/dao/FeedDao.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,15 @@
+package org.jboss.blog.session.feed.dao;
+
+import org.jboss.blog.model.RestrictedPost;
+import org.jboss.blog.session.update.UpdateException;
+
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public interface FeedDao {
+ public List<? extends RestrictedPost> getPosts(int from, int to, boolean restricted);
+
+ public void update() throws UpdateException;
+}
Added: feeds100P26/src/action/org/jboss/blog/session/feed/dao/HighlightsFeedDao.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/feed/dao/HighlightsFeedDao.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/feed/dao/HighlightsFeedDao.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,45 @@
+package org.jboss.blog.session.feed.dao;
+
+import org.jboss.blog.model.feed.HighlightsFeed;
+import org.jboss.blog.model.RestrictedPost;
+import org.jboss.blog.model.Post;
+import org.jboss.blog.session.feed.type.FeedType;
+import org.jboss.blog.session.update.UpdateException;
+import org.jboss.blog.session.security.tools.FeedSecurityTools;
+import org.jboss.blog.tools.GeneralTools;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at FeedType(
+ name = "highlights",
+ addPage = "/manage/highlights/highlights_add.xhtml",
+ editPage = "/manage/highlights/highlights_edit.xhtml",
+ model = HighlightsFeed.class)
+public class HighlightsFeedDao implements FeedDao {
+ private HighlightsFeed highlightsFeed;
+
+ public HighlightsFeedDao(HighlightsFeed highlightsFeed) {
+ this.highlightsFeed = highlightsFeed;
+ }
+
+ public List<? extends RestrictedPost> getPosts(int from, int to, boolean restricted) {
+ List<Post> posts = GeneralTools.subList(highlightsFeed.getSelectedPosts(), from, to);
+ List<Post> ret = new ArrayList<Post>();
+
+ for (Post post : posts) {
+ if (FeedSecurityTools.canViewFeed(post.getFeed(), restricted)) {
+ ret.add(post);
+ }
+ }
+
+ return ret;
+ }
+
+ public void update() throws UpdateException {
+
+ }
+}
\ No newline at end of file
Added: feeds100P26/src/action/org/jboss/blog/session/feed/dao/IndividualPostsFeedDao.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/feed/dao/IndividualPostsFeedDao.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/feed/dao/IndividualPostsFeedDao.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,36 @@
+package org.jboss.blog.session.feed.dao;
+
+import org.jboss.blog.model.feed.IndividualPostsFeed;
+import org.jboss.blog.model.RestrictedPost;
+import org.jboss.blog.session.feed.posts.DatabaseFeedPosts;
+import org.jboss.blog.session.feed.type.FeedType;
+import org.jboss.blog.session.feed.update.IndividualPostsFeedUpdate;
+import org.jboss.blog.session.update.UpdateException;
+import org.jboss.seam.Component;
+
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at FeedType(
+ name = "individual posts",
+ addPage = "/manage/individual/individual_add.xhtml",
+ editPage = "/manage/individual/individual_edit.xhtml",
+ model = IndividualPostsFeed.class)
+public class IndividualPostsFeedDao implements FeedDao {
+ private IndividualPostsFeed individualPostsFeed;
+
+ public IndividualPostsFeedDao(IndividualPostsFeed individualPostsFeed) {
+ this.individualPostsFeed = individualPostsFeed;
+ }
+
+ public List<? extends RestrictedPost> getPosts(int from, int to, boolean restricted) {
+ return ((DatabaseFeedPosts) Component.getInstance("databaseFeedPosts")).getPosts(
+ individualPostsFeed, from, to);
+ }
+
+ public void update() throws UpdateException {
+ ((IndividualPostsFeedUpdate) Component.getInstance("individualPostsFeedUpdate")).update(individualPostsFeed);
+ }
+}
\ No newline at end of file
Added: feeds100P26/src/action/org/jboss/blog/session/feed/dao/RemoteFeedDao.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/feed/dao/RemoteFeedDao.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/feed/dao/RemoteFeedDao.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,36 @@
+package org.jboss.blog.session.feed.dao;
+
+import org.jboss.blog.model.feed.RemoteFeed;
+import org.jboss.blog.model.RestrictedPost;
+import org.jboss.blog.session.feed.posts.DatabaseFeedPosts;
+import org.jboss.blog.session.feed.type.FeedType;
+import org.jboss.blog.session.feed.update.RemoteFeedUpdate;
+import org.jboss.blog.session.update.UpdateException;
+import org.jboss.seam.Component;
+
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at FeedType(
+ name = "remote",
+ addPage = "/manage/remote/remote_add.xhtml",
+ editPage = "/manage/remote/remote_edit.xhtml",
+ model = RemoteFeed.class)
+public class RemoteFeedDao implements FeedDao {
+ private RemoteFeed remoteFeed;
+
+ public RemoteFeedDao(RemoteFeed remoteFeed) {
+ this.remoteFeed = remoteFeed;
+ }
+
+ public List<? extends RestrictedPost> getPosts(int from, int to, boolean restricted) {
+ return ((DatabaseFeedPosts) Component.getInstance("databaseFeedPosts")).getPosts(
+ remoteFeed, from, to);
+ }
+
+ public void update() throws UpdateException {
+ ((RemoteFeedUpdate) Component.getInstance("remoteFeedUpdate")).update(remoteFeed);
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/feed/lock/FeedsLocksBean.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/feed/lock/FeedsLocksBean.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/feed/lock/FeedsLocksBean.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,37 @@
+package org.jboss.blog.session.feed.lock;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.ScopeType;
+
+import javax.annotation.PostConstruct;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.Map;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("feedsLocks")
+ at Scope(ScopeType.APPLICATION)
+ at AutoCreate
+public class FeedsLocksBean {
+ private Map<String, Lock> locks;
+
+ @PostConstruct
+ public void init() {
+ locks = new ConcurrentHashMap<String, Lock>();
+ }
+
+ public Lock getLockForFeed(String feedName) {
+ synchronized(this) {
+ if (!locks.containsKey(feedName)) {
+ locks.put(feedName, new ReentrantLock());
+ }
+ }
+
+ return locks.get(feedName);
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/feed/mod/AggregatedDeleteListener.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/feed/mod/AggregatedDeleteListener.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/feed/mod/AggregatedDeleteListener.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,57 @@
+package org.jboss.blog.session.feed.mod;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.Observer;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.ScopeType;
+import org.jboss.blog.model.Group;
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.feed.AggregatedFeed;
+import org.jboss.blog.service.GroupsService;
+
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("aggregatedDeleteListener")
+ at Scope(ScopeType.STATELESS)
+public class AggregatedDeleteListener {
+ @In
+ private GroupsService groupsService;
+
+ private void deleteFrom(Feed feedToDelete, List<Feed> feeds) {
+ for (Feed feed : feeds) {
+ if (feed instanceof AggregatedFeed) {
+ AggregatedFeed aggregatedFeed = (AggregatedFeed) feed;
+ aggregatedFeed.getFeeds().remove(feedToDelete);
+ }
+ }
+ }
+
+ private void deleteFrom(Group groupToDelete, List<Feed> feeds) {
+ for (Feed feed : feeds) {
+ if (feed instanceof AggregatedFeed) {
+ AggregatedFeed aggregatedFeed = (AggregatedFeed) feed;
+ aggregatedFeed.getGroups().remove(groupToDelete);
+ }
+ }
+ }
+
+ @Observer("org.jboss.blog.feed.before_delete")
+ public void beforeFeedDeleted(Feed feedToDelete) {
+ for (Group group : groupsService.getAllGroups()) {
+ deleteFrom(feedToDelete, groupsService.acceptedFeeds(group));
+ deleteFrom(feedToDelete, groupsService.unacceptedFeeds(group));
+ }
+ }
+
+ @Observer("org.jboss.blog.group.before_delete")
+ public void beforeGroupDeleted(Group groupToDelete) {
+ for (Group group : groupsService.getAllGroups()) {
+ deleteFrom(groupToDelete, groupsService.acceptedFeeds(group));
+ deleteFrom(groupToDelete, groupsService.unacceptedFeeds(group));
+ }
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/feed/mod/AggregatedFeedModBean.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/feed/mod/AggregatedFeedModBean.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/feed/mod/AggregatedFeedModBean.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,227 @@
+package org.jboss.blog.session.feed.mod;
+
+import org.jboss.blog.model.feed.AggregatedFeed;
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.Group;
+import org.jboss.blog.model.post.PostFilter;
+import org.jboss.blog.service.GroupsService;
+import org.jboss.blog.session.feed.InvalidFeedTypeException;
+import org.jboss.blog.session.security.tools.FeedSecurityTools;
+import org.jboss.blog.model.post.filter.AndFilter;
+import org.jboss.blog.tools.GeneralTools;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.core.Events;
+import org.jboss.seam.faces.FacesMessages;
+import org.jboss.seam.annotations.*;
+import org.jboss.seam.annotations.security.Restrict;
+
+import javax.faces.application.FacesMessage;
+import javax.persistence.EntityManager;
+import java.io.Serializable;
+import java.util.*;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Scope(ScopeType.CONVERSATION)
+ at Name("aggregatedFeedMod")
+public class AggregatedFeedModBean implements Serializable {
+ @In
+ private FeedModBean feedMod;
+
+ @In
+ private EntityManager entityManager;
+
+ @In
+ private FacesMessages facesMessages;
+
+ @In
+ private GroupsService groupsService;
+
+ private AggregatedFeed aggregatedFeed;
+
+ private List<Feed> availableFeeds;
+
+ private Map<Feed, Boolean> selectedFeeds;
+
+ private Map<Feed, List<PostFilter>> selectedFeedsFilters;
+
+ private List<Group> availableGroups;
+
+ private Map<Group, Boolean> selectedGroups;
+
+ private Map<Group, List<PostFilter>> selectedGroupsFilters;
+
+ private List<PostFilter> globalFilters;
+
+ public AggregatedFeed getAggregatedFeed() throws InvalidFeedTypeException {
+ if (aggregatedFeed == null) {
+ if (feedMod.getFeed() == null) {
+ aggregatedFeed = new AggregatedFeed();
+ aggregatedFeed.setFeeds(new HashMap<Feed, PostFilter>());
+ aggregatedFeed.setGroups(new HashMap<Group, PostFilter>());
+ aggregatedFeed.setGlobalFilter(new AndFilter());
+
+ feedMod.initNewFeed(aggregatedFeed);
+ aggregatedFeed.setLink(null);
+ } else {
+ if (feedMod.getFeed() instanceof AggregatedFeed) {
+ aggregatedFeed = (AggregatedFeed) feedMod.getFeed();
+ } else {
+ throw new InvalidFeedTypeException();
+ }
+ }
+ }
+
+ return aggregatedFeed;
+ }
+
+ private void fillPostFilterList(List<PostFilter> toFill, PostFilter source) {
+ if (source instanceof AndFilter) {
+ AndFilter andFilter = (AndFilter) source;
+ for (PostFilter filter : andFilter.getFilters()) {
+ toFill.add(filter);
+ }
+ }
+ }
+
+ private <T> void readSelectedEntities(List<T> availableEntities, Map<T, PostFilter> currentEntities,
+ Map<T, Boolean> selectedEntities,
+ Map<T, List<PostFilter>> selectedEntitiesFilters) {
+ // Populating individual filters
+ for (T entity : availableEntities) {
+ selectedEntitiesFilters.put(entity, new ArrayList<PostFilter>());
+
+ if (currentEntities.containsKey(entity)) {
+ fillPostFilterList(selectedEntitiesFilters.get(entity), currentEntities.get(entity));
+ }
+ }
+
+ // Populating selected entities
+ for (T entity : availableEntities) {
+ selectedEntities.put(entity, currentEntities.containsKey(entity));
+ }
+ }
+
+ @Create
+ public void populateLists() throws InvalidFeedTypeException {
+ // Populating available groups
+ availableGroups = groupsService.getAllGroups();
+ availableFeeds = new ArrayList<Feed>();
+
+ for (Group availableGroup : availableGroups) {
+ for (Feed nextFeed : groupsService.acceptedFeeds(availableGroup)) {
+ if (GeneralTools.objectsEqual(nextFeed, getAggregatedFeed())) {
+ continue;
+ }
+
+ availableFeeds.add(nextFeed);
+ }
+
+ for (Feed nextFeed : groupsService.restrictedFeeds(availableGroup)) {
+ if (GeneralTools.objectsEqual(nextFeed, getAggregatedFeed())) {
+ continue;
+ }
+
+ if (FeedSecurityTools.canViewFeed(nextFeed, true)) {
+ availableFeeds.add(nextFeed);
+ }
+ }
+ }
+
+ selectedFeedsFilters = new HashMap<Feed, List<PostFilter>>();
+ selectedFeeds = new HashMap<Feed, Boolean>();
+ readSelectedEntities(availableFeeds, getAggregatedFeed().getFeeds(), selectedFeeds, selectedFeedsFilters);
+
+ selectedGroupsFilters = new HashMap<Group, List<PostFilter>>();
+ selectedGroups = new HashMap<Group, Boolean>();
+ readSelectedEntities(availableGroups, getAggregatedFeed().getGroups(), selectedGroups, selectedGroupsFilters);
+
+ // Populating global filters
+ globalFilters = new ArrayList<PostFilter>();
+ fillPostFilterList(globalFilters, getAggregatedFeed().getGlobalFilter());
+ }
+
+ //
+
+ public List<Feed> getAvailableFeeds() {
+ return availableFeeds;
+ }
+
+ public Map<Feed, Boolean> getSelectedFeeds() {
+ return selectedFeeds;
+ }
+
+ public void setSelectedFeeds(Map<Feed, Boolean> selectedFeeds) {
+ this.selectedFeeds = selectedFeeds;
+ }
+
+ public Map<Feed, List<PostFilter>> getSelectedFeedsFilters() {
+ return selectedFeedsFilters;
+ }
+
+ //
+
+ public List<Group> getAvailableGroups() {
+ return availableGroups;
+ }
+
+ public Map<Group, Boolean> getSelectedGroups() {
+ return selectedGroups;
+ }
+
+ public void setSelectedGroups(Map<Group, Boolean> selectedGroups) {
+ this.selectedGroups = selectedGroups;
+ }
+
+ public Map<Group, List<PostFilter>> getSelectedGroupsFilters() {
+ return selectedGroupsFilters;
+ }
+
+ //
+
+ public List<PostFilter> getGlobalFilters() {
+ return globalFilters;
+ }
+
+ public void removeFilter(List<PostFilter> filters, PostFilter filter) {
+ filters.remove(filter);
+ }
+
+ private <T> void saveSelectedEntities(Map<T, PostFilter> currentEntities, Map<T, Boolean> selectedEntities,
+ Map<T, List<PostFilter>> selectedEntitiesFilters) {
+ currentEntities.clear();
+
+ for (T entity : selectedEntities.keySet()) {
+ if (selectedEntities.get(entity)) {
+ currentEntities.put(entity, new AndFilter(selectedEntitiesFilters.get(entity)));
+ }
+ }
+ }
+
+ private void save() throws InvalidFeedTypeException {
+ // Saving feeds and filters
+ saveSelectedEntities(getAggregatedFeed().getFeeds(), selectedFeeds, selectedFeedsFilters);
+
+ // Saving groups and filters
+ saveSelectedEntities(getAggregatedFeed().getGroups(), selectedGroups, selectedGroupsFilters);
+
+ // Saving global filters
+ getAggregatedFeed().setGlobalFilter(new AndFilter(globalFilters));
+ }
+
+ public void saveNew() throws InvalidFeedTypeException {
+ save();
+ }
+
+ @Restrict("#{identity.hasPermission('feed', 'edit', feedMod.feed, feedMod.feed.group)}")
+ public void saveExisting() throws InvalidFeedTypeException {
+ save();
+ entityManager.flush();
+
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, "blog.feed.aggregated.updated",
+ getAggregatedFeed().getName());
+
+ Events.instance().raiseEvent("org.jboss.blog.feed.updated", getAggregatedFeed());
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/feed/mod/FeedModBean.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/feed/mod/FeedModBean.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/feed/mod/FeedModBean.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,139 @@
+package org.jboss.blog.session.feed.mod;
+
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.feed.PostAuthorType;
+import org.jboss.blog.model.Post;
+import org.jboss.blog.model.Template;
+import org.jboss.blog.model.XmlType;
+import org.jboss.blog.session.merge.MergeServiceBean;
+import org.jboss.blog.session.feed.lock.FeedsLocksBean;
+import org.jboss.blog.session.update.UpdateHandlerAsync;
+import org.jboss.blog.session.xml.velocity.TemplateServiceBean;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.core.Events;
+import org.jboss.seam.annotations.*;
+import org.jboss.seam.annotations.security.Restrict;
+import org.jboss.seam.faces.FacesMessages;
+
+import javax.faces.application.FacesMessage;
+import javax.persistence.EntityManager;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.ArrayList;
+import java.util.concurrent.locks.Lock;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Scope(ScopeType.CONVERSATION)
+ at Name("feedMod")
+ at AutoCreate
+public class FeedModBean implements Serializable {
+ private Feed feed;
+
+ @In
+ private EntityManager entityManager;
+
+ @In
+ private FacesMessages facesMessages;
+
+ @In
+ private MergeServiceBean mergeService;
+
+ @In
+ private FeedsLocksBean feedsLocks;
+
+ @In
+ private UpdateHandlerAsync updateHandlerAsync;
+
+ @In
+ private TemplateServiceBean templateService;
+
+ @In
+ private Events events;
+
+ public void initNewFeed(Feed feed) {
+ this.feed = feed;
+ feed.setMaxPostsInFeed(10);
+ feed.setMaxPostsOnPage(10);
+ feed.setTemplates(new HashMap<XmlType, Template>());
+ feed.setAccepted(true);
+ feed.setPosts(new ArrayList<Post>());
+ feed.setPostAuthorType(PostAuthorType.BLOG_AUTHOR_IF_MISSING);
+
+ feed.getTemplates().put(XmlType.ATOM, templateService.templatesOfType(XmlType.ATOM).get(0));
+ feed.getTemplates().put(XmlType.RSS2, templateService.templatesOfType(XmlType.RSS2).get(0));
+ feed.getTemplates().put(XmlType.RSS1, templateService.templatesOfType(XmlType.RSS1).get(0));
+ }
+
+ public Feed getFeed() {
+ return feed;
+ }
+
+ public void setFeed(Feed feed) {
+ this.feed = feed;
+ }
+
+ public XmlType[] getTemplateTypes() {
+ return new XmlType[] { XmlType.ATOM, XmlType.RSS2 };
+ }
+
+ @Observer("org.jboss.blog.feed.accept")
+ public void acceptFeed() {
+ feed.setAccepted(true);
+
+ entityManager.flush();
+
+ updateHandlerAsync.update(feed);
+
+ events.raiseEvent("org.jboss.blog.feed.accepted", getFeed());
+
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, "blog.feed.accepted", getFeed().getName());
+ }
+
+ @Observer("org.jboss.blog.feed.proposed")
+ public void proposedFeed() {
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, "blog.feed.proposed", getFeed().getName());
+ }
+
+ @Restrict("#{identity.hasPermission('feed', 'add', feedMod.feed, feedMod.feed.group)}")
+ public void saveNew() {
+ Lock feedLock = feedsLocks.getLockForFeed(feed.getName());
+ feedLock.lock();
+ try {
+ entityManager.persist(feed);
+
+ for (Post post : feed.getPosts()) {
+ mergeService.savePost(feed, post);
+ }
+
+ entityManager.flush();
+ } finally {
+ feedLock.unlock();
+ }
+
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, "blog.feed.added", getFeed().getName());
+
+ events.raiseEvent("org.jboss.blog.feed.added", getFeed());
+ }
+
+ @Restrict("#{identity.hasPermission('feed', 'edit', feedMod.feed, feedMod.feed.group)}")
+ public void saveExisting() {
+ entityManager.flush();
+
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, "blog.feed.updated", getFeed().getName());
+
+ events.raiseEvent("org.jboss.blog.feed.updated", getFeed());
+ }
+
+ @Restrict("#{identity.hasPermission('feed', 'delete', feedMod.feed, feedMod.feed.group)}")
+ public void delete() {
+ events.raiseEvent("org.jboss.blog.feed.before_delete", getFeed());
+
+ entityManager.remove(getFeed());
+
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, "blog.feed.deleted", getFeed().getName());
+
+ events.raiseEvent("org.jboss.blog.feed.deleted", getFeed());
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/feed/mod/FilterAddBean.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/feed/mod/FilterAddBean.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/feed/mod/FilterAddBean.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,71 @@
+package org.jboss.blog.session.feed.mod;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.ScopeType;
+import org.jboss.blog.model.post.PostFilter;
+import org.jboss.blog.model.post.filter.PodcastFilter;
+import org.jboss.blog.model.post.filter.NotPodcastFilter;
+import org.jboss.blog.model.post.filter.CategoryRegexpFilter;
+
+import java.util.List;
+import java.io.Serializable;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("filterAdd")
+ at Scope(ScopeType.CONVERSATION)
+public class FilterAddBean implements Serializable {
+ private List<PostFilter> addToList;
+
+ private PodcastFilter podcastFilter;
+
+ private NotPodcastFilter notPodcastFilter;
+
+ private CategoryRegexpFilter authorRegexpFilter;
+
+ private CategoryRegexpFilter categoryRegexpFilter;
+
+ public PodcastFilter getPodcastFilter() {
+ if (podcastFilter == null) {
+ podcastFilter = new PodcastFilter();
+ }
+
+ return podcastFilter;
+ }
+
+ public NotPodcastFilter getNotPodcastFilter() {
+ if (notPodcastFilter == null) {
+ notPodcastFilter = new NotPodcastFilter();
+ }
+
+ return notPodcastFilter;
+ }
+
+ public CategoryRegexpFilter getAuthorRegexpFilter() {
+ if (authorRegexpFilter == null) {
+ authorRegexpFilter = new CategoryRegexpFilter();
+ }
+
+ return authorRegexpFilter;
+ }
+
+ public CategoryRegexpFilter getCategoryRegexpFilter() {
+ if (categoryRegexpFilter == null) {
+ categoryRegexpFilter = new CategoryRegexpFilter();
+ }
+
+ return categoryRegexpFilter;
+ }
+
+ public void add(PostFilter filter) {
+ addToList.add(filter);
+ }
+
+ public void addToList(List<PostFilter> addToList) {
+ this.addToList = addToList;
+ }
+
+ public void cancel() { }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/feed/mod/HighlightsDeleteListener.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/feed/mod/HighlightsDeleteListener.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/feed/mod/HighlightsDeleteListener.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,31 @@
+package org.jboss.blog.session.feed.mod;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.Observer;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.ScopeType;
+import org.jboss.blog.model.Post;
+import org.jboss.blog.model.feed.HighlightsFeed;
+
+import javax.persistence.EntityManager;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("highlightsDeleteListener")
+ at Scope(ScopeType.STATELESS)
+public class HighlightsDeleteListener {
+ @In
+ private EntityManager entityManager;
+
+ @Observer("org.jboss.blog.post.before_delete")
+ public void beforePostDeleted(Post postToDelete) {
+ for (Object feedObj : entityManager.createQuery("select feed from HighlightsFeed feed").getResultList()) {
+ HighlightsFeed feed = (HighlightsFeed) feedObj;
+ feed.getSelectedPosts().remove(postToDelete);
+ }
+
+ entityManager.flush();
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/feed/mod/HighlightsFeedModBean.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/feed/mod/HighlightsFeedModBean.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/feed/mod/HighlightsFeedModBean.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,138 @@
+package org.jboss.blog.session.feed.mod;
+
+import org.jboss.blog.model.feed.HighlightsFeed;
+import org.jboss.blog.model.Post;
+import org.jboss.blog.session.feed.InvalidFeedTypeException;
+import org.jboss.blog.tools.GeneralTools;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.core.Events;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.security.Restrict;
+import org.jboss.seam.faces.FacesMessages;
+
+import javax.faces.application.FacesMessage;
+import javax.persistence.EntityManager;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Scope(ScopeType.CONVERSATION)
+ at Name("highlightsFeedMod")
+public class HighlightsFeedModBean implements Serializable {
+ @In
+ private FeedModBean feedMod;
+
+ @In
+ private EntityManager entityManager;
+
+ @In
+ private FacesMessages facesMessages;
+
+ private HighlightsFeed highlightsFeed;
+
+ private Post post;
+
+ private HighlightsFeed selectedFeed;
+
+ private int[] positions;
+
+ private void initPositions(List<Post> posts) {
+ positions = new int[posts.size()];
+ for (int i=0; i<positions.length; i++) {
+ positions[i] = i;
+ }
+ }
+
+ public HighlightsFeed getHighlightsFeed() throws InvalidFeedTypeException {
+ if (highlightsFeed == null) {
+ if (feedMod.getFeed() == null) {
+ highlightsFeed = new HighlightsFeed();
+ feedMod.initNewFeed(highlightsFeed);
+
+ highlightsFeed.setSelectedPosts(new ArrayList<Post>());
+ } else {
+ if (feedMod.getFeed() instanceof HighlightsFeed) {
+ highlightsFeed = (HighlightsFeed) feedMod.getFeed();
+ } else {
+ throw new InvalidFeedTypeException();
+ }
+ }
+
+ initPositions(highlightsFeed.getSelectedPosts());
+ }
+
+ return highlightsFeed;
+ }
+
+ public HighlightsFeed getSelectedFeed() {
+ return selectedFeed;
+ }
+
+ public void setSelectedFeed(HighlightsFeed selectedFeed) {
+ this.selectedFeed = selectedFeed;
+ }
+
+ public Post getPost() {
+ return post;
+ }
+
+ public void setPost(Post post) {
+ this.post = post;
+ }
+
+ public int[] getPositions() {
+ return positions;
+ }
+
+ public void setPositions(int[] positions) {
+ this.positions = positions;
+ }
+
+ public void moveUp(int rowNumber) throws InvalidFeedTypeException {
+ GeneralTools.moveElement(getHighlightsFeed().getSelectedPosts(), rowNumber, rowNumber-1);
+ }
+
+ public void moveDown(int rowNumber) throws InvalidFeedTypeException {
+ GeneralTools.moveElement(getHighlightsFeed().getSelectedPosts(), rowNumber, rowNumber+1);
+ }
+
+ public void moveTo(int rowNumber) throws InvalidFeedTypeException {
+ GeneralTools.moveElement(getHighlightsFeed().getSelectedPosts(), rowNumber, positions[rowNumber]);
+ positions[rowNumber] = rowNumber;
+ }
+
+ public void delete(int rowNumber) throws InvalidFeedTypeException {
+ getHighlightsFeed().getSelectedPosts().remove(rowNumber);
+
+ initPositions(getHighlightsFeed().getSelectedPosts());
+ }
+
+ @Restrict("#{identity.hasPermission('feed', 'edit', feedMod.feed, feedMod.feed.group)}")
+ public void saveExisting() throws InvalidFeedTypeException {
+ entityManager.flush();
+
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, "blog.feed.highlights.updated",
+ getHighlightsFeed().getName());
+
+ Events.instance().raiseEvent("org.jboss.blog.feed.updated", getHighlightsFeed());
+ }
+
+ @Restrict("#{identity.hasPermission('feed', 'edit', highlightsFeedMod.selectedFeed, highlightsFeedMod.selectedFeed.group)}")
+ public void addPost() {
+ if (!getSelectedFeed().getSelectedPosts().contains(getPost())) {
+ getSelectedFeed().getSelectedPosts().add(getPost());
+
+ entityManager.flush();
+
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, "blog.feed.highlights.post.added",
+ getPost().getTitle(), getSelectedFeed().getName());
+
+ Events.instance().raiseEvent("org.jboss.blog.feed.updated", getSelectedFeed());
+ }
+ }
+}
\ No newline at end of file
Added: feeds100P26/src/action/org/jboss/blog/session/feed/mod/IndividualFeedModBean.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/feed/mod/IndividualFeedModBean.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/feed/mod/IndividualFeedModBean.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,291 @@
+package org.jboss.blog.session.feed.mod;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.security.Restrict;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.core.Events;
+import org.jboss.seam.faces.FacesMessages;
+import org.jboss.blog.model.feed.IndividualPostsFeed;
+import org.jboss.blog.model.feed.IndividualPostInfo;
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.Post;
+import org.jboss.blog.session.feed.InvalidFeedTypeException;
+import org.jboss.blog.session.parser.ParserException;
+import org.jboss.blog.session.parser.ParserService;
+import org.jboss.blog.session.merge.MergeServiceBean;
+import org.jboss.blog.session.merge.PostManager;
+import org.jboss.blog.tools.GeneralTools;
+import org.jboss.blog.tools.StringTools;
+
+import javax.persistence.EntityManager;
+import javax.faces.application.FacesMessage;
+import javax.faces.model.SelectItem;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Scope(ScopeType.CONVERSATION)
+ at Name("individualFeedMod")
+public class IndividualFeedModBean {
+ @In
+ private FeedModBean feedMod;
+
+ @In
+ private EntityManager entityManager;
+
+ @In
+ private FacesMessages facesMessages;
+
+ @In
+ private Events events;
+
+ @In
+ private ParserService parserService;
+
+ @In
+ private PostsValidator postsValidator;
+
+ @In
+ private MergeServiceBean mergeService;
+
+ @In
+ private PostManager postManager;
+
+ private IndividualPostsFeed individualPostsFeed;
+
+ private String address;
+
+ private boolean parseOk;
+
+ private Feed parsedFeed;
+
+ private Post selectedPost;
+
+ private String selectedPostTitleAsId;
+
+ private String postAuthor;
+
+ private List<SelectItem> posts;
+
+ private List<IndividualPostInfo> postInfos;
+
+ private int from;
+
+ public IndividualPostsFeed getIndividualPostsFeed() throws InvalidFeedTypeException {
+ if (individualPostsFeed == null) {
+ if (feedMod.getFeed() == null) {
+ individualPostsFeed = new IndividualPostsFeed();
+ feedMod.initNewFeed(individualPostsFeed);
+
+ individualPostsFeed.setPostInfos(new ArrayList<IndividualPostInfo>());
+ } else {
+ if (feedMod.getFeed() instanceof IndividualPostsFeed) {
+ individualPostsFeed = (IndividualPostsFeed) feedMod.getFeed();
+ } else {
+ throw new InvalidFeedTypeException();
+ }
+ }
+ }
+
+ return individualPostsFeed;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+ public boolean isParseOk() {
+ return parseOk;
+ }
+
+ public void setParseOk(boolean parseOk) {
+ this.parseOk = parseOk;
+ }
+
+ public Feed getParsedFeed() {
+ return parsedFeed;
+ }
+
+ public void setParsedFeed(Feed parsedFeed) {
+ this.parsedFeed = parsedFeed;
+ }
+
+ public Post getSelectedPost() {
+ return selectedPost;
+ }
+
+ public void setSelectedPost(Post selectedPost) {
+ this.selectedPost = selectedPost;
+ }
+
+ public String getSelectedPostTitleAsId() {
+ return selectedPostTitleAsId;
+ }
+
+ public int getFrom() {
+ return from;
+ }
+
+ public void setFrom(int from) {
+ if (this.from != from) {
+ postInfos = null;
+ }
+
+ this.from = from;
+ }
+
+ public int getPostsOnPage() {
+ return 10;
+ }
+
+ public boolean getShowPrevious() {
+ return from != 0;
+ }
+
+ public boolean getShowNext() throws InvalidFeedTypeException {
+ return getPostInfos().size() == getPostsOnPage()+1;
+ }
+
+ public int getPreviousFrom() {
+ return Math.max(0, from - getPostsOnPage());
+ }
+
+ public int getNextFrom() {
+ return from + getPostsOnPage();
+ }
+
+ public List<IndividualPostInfo> getPostInfos() throws InvalidFeedTypeException {
+ if (postInfos == null) {
+ //noinspection unchecked
+ postInfos = entityManager
+ .createQuery("SELECT pi FROM IndividualPostInfo pi WHERE pi.feed = ?1 ORDER BY pi.post.published DESC")
+ .setParameter(1, getIndividualPostsFeed())
+ .setFirstResult(from)
+ .setMaxResults(getPostsOnPage()+1)
+ .getResultList();
+ }
+
+ return postInfos;
+ }
+
+ public void setPostInfos(List<IndividualPostInfo> postInfos) {
+ this.postInfos = postInfos;
+ }
+
+ public void setSelectedPostTitleAsId(String selectedPostTitleAsId) {
+ this.selectedPostTitleAsId = selectedPostTitleAsId;
+
+ if (parsedFeed != null) {
+ for (Post post : parsedFeed.getPosts()) {
+ if (GeneralTools.objectsEqual(post.getTitleAsId(), selectedPostTitleAsId)) {
+ selectedPost = post;
+ break;
+ }
+ }
+ }
+ }
+
+ public String getPostAuthor() {
+ return postAuthor;
+ }
+
+ public void setPostAuthor(String postAuthor) {
+ this.postAuthor = postAuthor;
+ }
+
+ public List<SelectItem> getPosts() {
+ return posts;
+ }
+
+ public void setPosts(List<SelectItem> posts) {
+ this.posts = posts;
+ }
+
+ public void updateSelectedPost() {
+ if (!StringTools.isEmpty(selectedPost.getAuthor())) {
+ postAuthor = selectedPost.getAuthor();
+ }
+ }
+
+ public void parseFeed() {
+ try {
+ parsedFeed = parserService.parse(getAddress());
+
+ if (!postsValidator.validatePosts(parsedFeed.getPosts(), true, "address")) {
+ throw new ParserException("Posts are missing some information.");
+ }
+
+ postAuthor = parsedFeed.getAuthor();
+
+ posts = new ArrayList<SelectItem>();
+ for (Post post : parsedFeed.getPosts()) {
+ posts.add(new SelectItem(post.getTitleAsId(), post.getTitle()));
+ }
+
+ if (parsedFeed.getPosts().size() > 0) {
+ selectedPost = parsedFeed.getPosts().get(0);
+ updateSelectedPost();
+ }
+
+ setParseOk(true);
+ } catch (ParserException e) {
+ facesMessages.addToControlFromResourceBundle("parse", FacesMessage.SEVERITY_ERROR,
+ "blog.feed.remote.parsenotok", e.getMessage());
+
+ setParseOk(false);
+ }
+ }
+
+ public void reset() {
+ parseOk = false;
+ address = "";
+ selectedPost = null;
+ selectedPostTitleAsId = null;
+ postInfos = null;
+ }
+
+ @Restrict("#{identity.hasPermission('feed', 'edit', feedMod.feed, feedMod.feed.group)}")
+ public void addPost() throws InvalidFeedTypeException {
+ selectedPost.setAuthor(postAuthor);
+
+ mergeService.savePost(individualPostsFeed, selectedPost);
+
+ IndividualPostInfo postInfo = new IndividualPostInfo();
+ postInfo.setPost(selectedPost);
+ postInfo.setFeed(individualPostsFeed);
+ postInfo.setRemoteFeedAddress(address);
+
+ entityManager.persist(postInfo);
+
+ individualPostsFeed.getPostInfos().add(postInfo);
+
+ entityManager.flush();
+
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, "blog.feed.individual.post.added",
+ selectedPost.getTitle());
+
+ events.raiseEvent("org.jboss.blog.feed.updated", individualPostsFeed);
+
+ reset();
+ }
+
+ public void delete(IndividualPostInfo postInfo) throws InvalidFeedTypeException {
+ individualPostsFeed.getPostInfos().remove(postInfo);
+ entityManager.remove(postInfo);
+ postManager.deletePost(postInfo.getPost());
+
+ entityManager.flush();
+
+ events.raiseEvent("org.jboss.blog.feed.updated", individualPostsFeed);
+
+ reset();
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/feed/mod/PostsValidator.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/feed/mod/PostsValidator.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/feed/mod/PostsValidator.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,99 @@
+package org.jboss.blog.session.feed.mod;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.faces.FacesMessages;
+import org.jboss.seam.core.Validators;
+import org.jboss.blog.model.Post;
+import org.jboss.blog.model.Enclosure;
+import org.jboss.blog.model.Image;
+import org.hibernate.validator.InvalidValue;
+import org.hibernate.validator.ClassValidator;
+
+import javax.faces.application.FacesMessage;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Scope(ScopeType.STATELESS)
+ at Name("postsValidator")
+ at AutoCreate
+public class PostsValidator {
+ @In
+ private Validators validators;
+
+ @In
+ private FacesMessages facesMessages;
+
+ public boolean validatePosts(List<Post> posts, boolean checkLinks, String controlForMessages) {
+ ClassValidator<Post> postValidator = validators.getValidator(Post.class);
+ ClassValidator<Enclosure> enclosureValidator = validators.getValidator(Enclosure.class);
+ ClassValidator<Image> imageValidator = validators.getValidator(Image.class);
+
+ for (Post post : posts) {
+ InvalidValue[] invalidValues = postValidator.getInvalidValues(post);
+ if (invalidValues.length != 0) {
+ boolean validationFailed = false;
+
+ for (InvalidValue invalidValue : invalidValues) {
+ if ((checkLinks || !"link".equals(invalidValue.getPropertyName())) &&
+ (!"feed".equals(invalidValue.getPropertyName()))) {
+ validationFailed = true;
+
+ facesMessages.addToControlFromResourceBundle(controlForMessages, FacesMessage.SEVERITY_ERROR,
+ "blog.feed.post.invalid", post.getTitle(),
+ invalidValue.getPropertyName(), invalidValue.getMessage());
+ }
+ }
+
+ return !validationFailed;
+ }
+
+ for (Enclosure enc : post.getEnclosures()) {
+ invalidValues = enclosureValidator.getInvalidValues(enc);
+
+ if (invalidValues.length != 0) {
+ boolean validationFailed = false;
+
+ for (InvalidValue invalidValue : invalidValues) {
+ if (!"post".equals(invalidValue.getPropertyName())) {
+ validationFailed = true;
+
+ facesMessages.addToControlFromResourceBundle(controlForMessages, FacesMessage.SEVERITY_ERROR,
+ "blog.feed.enclosure.invalid", post.getTitle(), enc.getUrl(),
+ invalidValue.getPropertyName(), invalidValue.getMessage());
+ }
+ }
+
+ return !validationFailed;
+ }
+ }
+
+ for (Image image : post.getImages()) {
+ invalidValues = imageValidator.getInvalidValues(image);
+
+ if (invalidValues.length != 0) {
+ boolean validationFailed = false;
+
+ for (InvalidValue invalidValue : invalidValues) {
+ if (!"post".equals(invalidValue.getPropertyName())) {
+ validationFailed = true;
+
+ facesMessages.addToControlFromResourceBundle(controlForMessages, FacesMessage.SEVERITY_ERROR,
+ "blog.feed.enclosure.invalid", post.getTitle(),
+ invalidValue.getPropertyName(), invalidValue.getMessage());
+ }
+ }
+
+ return !validationFailed;
+ }
+ }
+ }
+
+ return true;
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/feed/mod/PropositionsListener.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/feed/mod/PropositionsListener.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/feed/mod/PropositionsListener.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,83 @@
+package org.jboss.blog.session.feed.mod;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Observer;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Logger;
+import org.jboss.seam.faces.Renderer;
+import org.jboss.seam.log.Log;
+import org.jboss.blog.model.log.PropositionsLog;
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.session.security.FeedsIdentity;
+import org.jboss.blog.session.configuration.ConfigurationManager;
+import org.jboss.blog.tools.StringTools;
+
+import javax.persistence.EntityManager;
+import java.util.Date;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("propositionsListener")
+public class PropositionsListener {
+ @In
+ private FeedModBean feedMod;
+
+ @In
+ private EntityManager entityManager;
+
+ @In(create = true)
+ private Renderer renderer;
+
+ @In
+ private FeedsIdentity identity;
+
+ @In
+ private ConfigurationManager configurationManager;
+
+ @In
+ private PropositionsToolsBean propositionsTools;
+
+ @Logger
+ private Log log;
+
+ private String currentEmail;
+
+ public String getCurrentEmail() {
+ return currentEmail;
+ }
+
+ private void sendEmail(String email, String view) {
+ if (!StringTools.isEmpty(email)) {
+ try {
+ currentEmail = email;
+ renderer.render(view);
+ } catch (Exception e) {
+ log.warn(e);
+ }
+ }
+ }
+
+ @Observer("org.jboss.blog.feed.proposed")
+ public void feedProposed() {
+ entityManager.persist(new PropositionsLog(feedMod.getFeed(), identity.getSecurityUser(), new Date()));
+
+ sendEmail(feedMod.getFeed().getGroup().getAdminEmail(), "/emails/new_proposition_email.xhtml");
+ sendEmail(configurationManager.getConfiguration().getAdminEmail(), "/emails/new_proposition_email.xhtml");
+ }
+
+ @Observer("org.jboss.blog.feed.accepted")
+ public void feedAccepted(Feed feed) {
+ sendEmail(propositionsTools.getEmailForProposedFeed(feed), "/emails/proposition_accepted.xhtml");
+ }
+
+ @Observer("org.jboss.blog.feed.before_delete")
+ public void beforeFeedDeleted(Feed feed) {
+ if (!feed.isAccepted()) {
+ sendEmail(propositionsTools.getEmailForProposedFeed(feed), "/emails/proposition_rejected.xhtml");
+ }
+
+ entityManager.createQuery("delete from PropositionsLog pl where pl.feed = ?1")
+ .setParameter(1, feed).executeUpdate();
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/feed/mod/PropositionsToolsBean.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/feed/mod/PropositionsToolsBean.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/feed/mod/PropositionsToolsBean.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,62 @@
+package org.jboss.blog.session.feed.mod;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.ScopeType;
+import org.jboss.blog.service.GroupsService;
+import org.jboss.blog.model.Group;
+import org.jboss.blog.model.security.SecurityUser;
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.session.security.filtering.GroupsSecurity;
+import org.jboss.blog.session.security.external.ExternalSecurityService;
+
+import javax.persistence.NoResultException;
+import javax.persistence.EntityManager;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("propositionsTools")
+ at Scope(ScopeType.STATELESS)
+ at AutoCreate
+public class PropositionsToolsBean {
+ @In
+ private GroupsService groupsService;
+
+ @In
+ private GroupsSecurity groupsSecurity;
+
+ @In
+ private EntityManager entityManager;
+
+ @In
+ private ExternalSecurityService externalSecurityService;
+
+ public int getPendingPropositions() {
+ int total = 0;
+
+ for (Group group : groupsSecurity.filterForFeedMod(groupsService.getAllGroups())) {
+ total += groupsService.unacceptedFeeds(group).size();
+ }
+
+ return total;
+ }
+
+ public String getEmailForProposedFeed(Feed feed) {
+ try {
+ SecurityUser securityUser = (SecurityUser) entityManager.createQuery(
+ "select pl.securityUser from PropositionsLog pl where pl.feed = ?1")
+ .setParameter(1, feed).getSingleResult();
+
+ if (securityUser != null) {
+ return externalSecurityService.getEmail(securityUser);
+ } else {
+ return null;
+ }
+ } catch (NoResultException e) {
+ return null;
+ }
+ }
+}
\ No newline at end of file
Added: feeds100P26/src/action/org/jboss/blog/session/feed/mod/RemoteFeedModBean.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/feed/mod/RemoteFeedModBean.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/feed/mod/RemoteFeedModBean.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,261 @@
+package org.jboss.blog.session.feed.mod;
+
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.feed.RemoteFeed;
+import org.jboss.blog.model.feed.PostAuthorType;
+import org.jboss.blog.model.Post;
+import org.jboss.blog.model.Category;
+import org.jboss.blog.session.feed.InvalidFeedTypeException;
+import org.jboss.blog.session.parser.ParserException;
+import org.jboss.blog.session.parser.ParserService;
+import org.jboss.blog.tools.StringTools;
+import org.jboss.blog.tools.PostFilterTools;
+import org.jboss.blog.tools.validator.Regexp;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.core.Events;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.security.Restrict;
+import org.jboss.seam.faces.FacesMessages;
+
+import javax.faces.application.FacesMessage;
+import javax.faces.model.SelectItem;
+import javax.persistence.EntityManager;
+import java.io.Serializable;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.regex.Pattern;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Scope(ScopeType.CONVERSATION)
+ at Name("remoteFeedMod")
+public class RemoteFeedModBean implements Serializable {
+ @In
+ private ParserService parserService;
+
+ @In
+ private FeedModBean feedMod;
+
+ @In
+ private EntityManager entityManager;
+
+ @In
+ private FacesMessages facesMessages;
+
+ @In
+ private PostsValidator postsValidator;
+
+ private List<SelectItem> includeCategories;
+
+ private String includeCategory;
+
+ @Regexp
+ private String includeOtherCategoryRegexp;
+
+ private List<Post> visiblePosts;
+
+ private RemoteFeed remoteFeed;
+
+ private Feed parsedFeed;
+
+ private boolean parseOk;
+
+ private final static String ALL_CATEGORIES = "ALL";
+ private final static String OTHER_CATEGORY = "OTHER";
+
+ public RemoteFeed getRemoteFeed() throws InvalidFeedTypeException {
+ if (remoteFeed == null) {
+ if (feedMod.getFeed() == null) {
+ remoteFeed = new RemoteFeed();
+ feedMod.initNewFeed(remoteFeed);
+
+ if (StringTools.isEmpty(remoteFeed.getLink())) {
+ remoteFeed.setLink(remoteFeed.getRemoteLink());
+ }
+ } else {
+ if (feedMod.getFeed() instanceof RemoteFeed) {
+ remoteFeed = (RemoteFeed) feedMod.getFeed();
+ if (StringTools.isEmpty(remoteFeed.getIncludeCategoryRegexp())) {
+ includeCategory = ALL_CATEGORIES;
+ } else {
+ includeCategory = OTHER_CATEGORY;
+ includeOtherCategoryRegexp = remoteFeed.getIncludeCategoryRegexp();
+ }
+
+ initIncludeCategories();
+ finishIncludeCategories();
+ } else {
+ throw new InvalidFeedTypeException();
+ }
+ }
+ }
+
+ return remoteFeed;
+ }
+
+ public boolean isParseOk() {
+ return parseOk;
+ }
+
+ public void setParseOk(boolean parseOk) {
+ this.parseOk = parseOk;
+ }
+
+ public List<SelectItem> getIncludeCategories() {
+ return includeCategories;
+ }
+
+ public String getIncludeCategory() {
+ return includeCategory;
+ }
+
+ public void setIncludeCategory(String includeCategory) throws InvalidFeedTypeException {
+ this.includeCategory = includeCategory;
+ }
+
+ public String getIncludeOtherCategoryRegexp() {
+ return includeOtherCategoryRegexp;
+ }
+
+ public void setIncludeOtherCategoryRegexp(String includeOtherCategoryRegexp) throws InvalidFeedTypeException {
+ this.includeOtherCategoryRegexp = includeOtherCategoryRegexp;
+ }
+
+ public List<Post> getVisiblePosts() {
+ return visiblePosts;
+ }
+
+ private void generateIncludedCategory() throws InvalidFeedTypeException {
+ if (ALL_CATEGORIES.equals(includeCategory)) {
+ getRemoteFeed().setIncludeCategoryRegexp(null);
+ } else if (OTHER_CATEGORY.equals(includeCategory)) {
+ getRemoteFeed().setIncludeCategoryRegexp(includeOtherCategoryRegexp);
+ } else {
+ getRemoteFeed().setIncludeCategoryRegexp(
+ includeCategory == null ? null : Pattern.quote(includeCategory));
+ }
+ }
+
+ public void generateVisiblePosts() throws InvalidFeedTypeException {
+ generateIncludedCategory();
+
+ RemoteFeed remoteFeed = getRemoteFeed();
+ visiblePosts = new ArrayList<Post>();
+
+ if (parsedFeed != null) {
+ for (Post post : parsedFeed.getPosts()) {
+ if (remoteFeed.getIncludeCategoryFilter().filter(post)) {
+ visiblePosts.add(post);
+ }
+ }
+ }
+ }
+
+ public void unsetAccepted() throws InvalidFeedTypeException {
+ getRemoteFeed().setAccepted(false);
+ }
+
+ private void initIncludeCategories() {
+ includeCategories = new ArrayList<SelectItem>();
+ includeCategories.add(new SelectItem(ALL_CATEGORIES, "All categories"));
+ }
+
+ private void finishIncludeCategories() {
+ includeCategories.add(new SelectItem(OTHER_CATEGORY, "Other (regular expression) ..."));
+ }
+
+ private Set<Category> getCategoriesOfPosts(Feed feed) {
+ Set<Category> categories = new HashSet<Category>();
+
+ for (Post post : feed.getPosts()) {
+ categories.addAll(post.getCategories());
+ }
+
+ return categories;
+ }
+
+ public void parseFeed() throws InvalidFeedTypeException {
+ try {
+ parsedFeed = parserService.parse(getRemoteFeed().getRemoteLink());
+
+ if (!postsValidator.validatePosts(parsedFeed.getPosts(), true, "link")) {
+ throw new ParserException("Posts are missing some information.");
+ }
+
+ initIncludeCategories();
+ Set<Category> categories = getCategoriesOfPosts(parsedFeed);
+ for (Category cat : categories) {
+ includeCategories.add(new SelectItem(cat.getName(), cat.getName()));
+ }
+ finishIncludeCategories();
+
+ generateVisiblePosts();
+
+ setParseOk(true);
+
+ if (categories.size() == 0) {
+ facesMessages.addToControlFromResourceBundle("parse", FacesMessage.SEVERITY_INFO,
+ "blog.feed.remote.parseok.nocategories");
+ } else {
+ facesMessages.addToControlFromResourceBundle("parse", FacesMessage.SEVERITY_INFO,
+ "blog.feed.remote.parseok.categories");
+ }
+ } catch (ParserException e) {
+ facesMessages.addToControlFromResourceBundle("parse", FacesMessage.SEVERITY_ERROR,
+ "blog.feed.remote.parsenotok", e.getMessage());
+
+ setParseOk(false);
+ }
+ }
+
+ public void saveNew() throws InvalidFeedTypeException {
+ RemoteFeed remoteFeed = getRemoteFeed();
+ remoteFeed.setAuthor(parsedFeed.getAuthor());
+ remoteFeed.setDescription(parsedFeed.getDescription());
+ remoteFeed.setLink(parsedFeed.getLink());
+ remoteFeed.setTitle(parsedFeed.getTitle());
+
+ generateIncludedCategory();
+
+ if (getRemoteFeed().isAccepted()) {
+ remoteFeed.setPosts(PostFilterTools.filterPostList(parsedFeed.getPosts(),
+ remoteFeed.getIncludeCategoryFilter()));
+ }
+ }
+
+ @Restrict("#{identity.hasPermission('feed', 'edit', feedMod.feed, feedMod.feed.group)}")
+ public void saveExisting() throws InvalidFeedTypeException {
+ getRemoteFeed().setLink(parsedFeed.getLink());
+
+ generateIncludedCategory();
+
+ entityManager.flush();
+
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, "blog.feed.remote.updated",
+ getRemoteFeed().getName());
+
+ Events.instance().raiseEvent("org.jboss.blog.feed.updated", getRemoteFeed());
+ }
+
+ @Restrict("#{identity.hasPermission('feed', 'edit', feedMod.feed, feedMod.feed.group)}")
+ public void savePartial() throws InvalidFeedTypeException {
+ PostAuthorType newPostAuthorType = getRemoteFeed().getPostAuthorType();
+
+ entityManager.refresh(getRemoteFeed());
+
+ getRemoteFeed().setPostAuthorType(newPostAuthorType);
+ generateIncludedCategory();
+
+ entityManager.flush();
+
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, "blog.feed.remote.updated",
+ getRemoteFeed().getName());
+
+ Events.instance().raiseEvent("org.jboss.blog.feed.updated", getRemoteFeed());
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/feed/posts/AggregatedFeedPosts.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/feed/posts/AggregatedFeedPosts.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/feed/posts/AggregatedFeedPosts.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,111 @@
+package org.jboss.blog.session.feed.posts;
+
+import org.jboss.blog.model.feed.AggregatedFeed;
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.RestrictedPost;
+import org.jboss.blog.model.Group;
+import org.jboss.blog.service.FeedsService;
+import org.jboss.blog.service.GroupsService;
+import org.jboss.blog.tools.GeneralTools;
+import org.jboss.blog.tools.PostFilterTools;
+import org.jboss.blog.model.post.PostFilter;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+
+import java.util.*;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("aggregatedFeedPosts")
+ at Scope(ScopeType.STATELESS)
+public class AggregatedFeedPosts {
+ @In
+ private FeedsService feedsService;
+
+ @In
+ private GroupsService groupsService;
+
+ @In
+ private AggregatedFeedStack aggregatedFeedStack;
+
+ @SuppressWarnings("unchecked")
+ public List<? extends RestrictedPost> getPosts(AggregatedFeed aggregatedFeed, int from, int to,
+ boolean restricted) {
+ if (aggregatedFeedStack.contains(aggregatedFeed)) {
+ return null;
+ }
+
+ // Adding this feed to the stack, so it's posts won't be read again.
+ aggregatedFeedStack.push(aggregatedFeed);
+
+ Map<Feed, PostFilter> feedsAndFilters = new HashMap<Feed, PostFilter>(aggregatedFeed.getFeeds());
+
+ Map<Group, PostFilter> groupsAndFilters = aggregatedFeed.getGroups();
+ for (Group group : groupsAndFilters.keySet()) {
+ PostFilter groupFilter = groupsAndFilters.get(group);
+ for (Feed feedInGroup : groupsService.acceptedFeeds(group)) {
+ feedsAndFilters.put(feedInGroup, groupFilter);
+ }
+
+ if (restricted) {
+ for (Feed feedInGroup : groupsService.restrictedFeeds(group)) {
+ feedsAndFilters.put(feedInGroup, groupFilter);
+ }
+ }
+ }
+
+ PostFilter globalFilter = aggregatedFeed.getGlobalFilter();
+
+ // Initial list of aggregated feeds.
+ Set<Feed> availableFeeds = feedsAndFilters.keySet();
+
+ // Generating the list of posts.
+ SortedSet<RestrictedPost> posts = new TreeSet<RestrictedPost>();
+
+ // Bounds for the number of posts read from each feed.
+ int feedPostsFrom = 0;
+ int feedPostsTo = to;
+
+ do {
+ // A list of feeds from which we may later read more posts, if necessary.
+ Set<Feed> newAvailableFeeds = new HashSet<Feed>();
+
+ for (Feed feed : availableFeeds) {
+ List<? extends RestrictedPost> feedPosts = feedsService.getPosts(feed, feedPostsFrom, feedPostsTo,
+ restricted);
+
+ if (feedPosts == null) {
+ continue;
+ }
+
+ // Checking if this feed has any more posts; if so, remembering it so it can be checked for more posts,
+ // if needed.
+ if (feedPosts.size() == feedPostsTo-feedPostsFrom) {
+ newAvailableFeeds.add(feed);
+ }
+
+ // Apply the local filters
+ PostFilterTools.filterFromPostList(feedPosts, feedsAndFilters.get(feed));
+
+ // Apply the global filters
+ PostFilterTools.filterFromPostList(feedPosts, globalFilter);
+
+ posts.addAll(feedPosts);
+ }
+
+ availableFeeds = newAvailableFeeds;
+
+ feedPostsFrom = feedPostsTo;
+ feedPostsTo += to;
+ } while (availableFeeds.size() != 0 && posts.size() < to);
+
+ // Popping this feed from the stack.
+ aggregatedFeedStack.pop();
+
+ // Cut the list to the desired length
+ return GeneralTools.subList(new ArrayList(posts), from, to);
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/feed/posts/AggregatedFeedStack.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/feed/posts/AggregatedFeedStack.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/feed/posts/AggregatedFeedStack.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,39 @@
+package org.jboss.blog.session.feed.posts;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.ScopeType;
+import org.jboss.blog.model.feed.AggregatedFeed;
+
+import javax.annotation.PostConstruct;
+import java.util.List;
+import java.util.ArrayList;
+import java.io.Serializable;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("aggregatedFeedStack")
+ at Scope(ScopeType.CONVERSATION)
+ at AutoCreate
+public class AggregatedFeedStack implements Serializable {
+ private List<AggregatedFeed> stack;
+
+ @PostConstruct
+ public void initStack() {
+ stack = new ArrayList<AggregatedFeed>();
+ }
+
+ public void push(AggregatedFeed feed) {
+ stack.add(feed);
+ }
+
+ public void pop() {
+ stack.remove(stack.size()-1);
+ }
+
+ public boolean contains(AggregatedFeed feed) {
+ return stack.contains(feed);
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/feed/posts/DatabaseFeedPosts.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/feed/posts/DatabaseFeedPosts.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/feed/posts/DatabaseFeedPosts.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,40 @@
+package org.jboss.blog.session.feed.posts;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.ScopeType;
+import org.jboss.blog.model.Post;
+import org.jboss.blog.model.RestrictedPost;
+import org.jboss.blog.model.feed.Feed;
+
+import javax.persistence.EntityManager;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("databaseFeedPosts")
+ at Scope(ScopeType.STATELESS)
+ at AutoCreate
+public class DatabaseFeedPosts {
+ @In
+ private EntityManager entityManager;
+
+ @SuppressWarnings("unchecked")
+ public List<? extends RestrictedPost> getPosts(Feed feed, int from, int to) {
+ return (List<Post>) entityManager.createQuery(
+ "select post from Post post where post.feed = ?1 order by post.published desc, post.link")
+ .setParameter(1, feed).setMaxResults(to-from).setFirstResult(from).getResultList();
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<? extends RestrictedPost> getPosts(int from, int to) {
+ return (List<Post>) entityManager.createQuery(
+ "select post from Post post where (post.feed.restricted is null or post.feed.restricted = false) " +
+ "order by post.published desc, post.link")
+ .setMaxResults(to-from).setFirstResult(from)
+ .setHint("org.hibernate.cacheable", Boolean.TRUE).getResultList();
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/feed/type/FeedType.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/feed/type/FeedType.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/feed/type/FeedType.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,22 @@
+package org.jboss.blog.session.feed.type;
+
+import org.jboss.blog.model.feed.Feed;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.TYPE)
+public @interface FeedType {
+ public String name();
+ public Class<? extends Feed> model();
+ public String addPage();
+ public String editPage();
+
+ //public String feedUpdateComponentName();
+}
Added: feeds100P26/src/action/org/jboss/blog/session/feed/type/FeedTypes.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/feed/type/FeedTypes.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/feed/type/FeedTypes.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,96 @@
+package org.jboss.blog.session.feed.type;
+
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.feed.RestrictedFeed;
+import org.jboss.blog.session.feed.InvalidFeedTypeException;
+import org.jboss.blog.session.feed.dao.FeedDao;
+import org.jboss.blog.session.scanner.ClassHandler;
+import org.jboss.blog.tools.KeySafeMap;
+import org.jboss.blog.tools.KeyNotMappedException;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.log.Log;
+import org.jboss.seam.annotations.*;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("feedTypes")
+ at Scope(ScopeType.APPLICATION)
+ at AutoCreate
+public class FeedTypes implements ClassHandler {
+ @Logger
+ private Log log;
+
+ private Map<Class<? extends RestrictedFeed>, FeedType> feedTypes;
+ private Map<Class<? extends RestrictedFeed>, Constructor<? extends FeedDao>> feedDaos;
+
+ public FeedTypes() {
+ feedTypes = KeySafeMap.wrap(new ConcurrentHashMap<Class<? extends RestrictedFeed>, FeedType>());
+ feedDaos = KeySafeMap.wrap(new ConcurrentHashMap<Class<? extends RestrictedFeed>,
+ Constructor<? extends FeedDao>>());
+ }
+
+ public FeedType[] getAllTypes() {
+ return feedTypes.values().toArray(new FeedType[feedTypes.size()]);
+ }
+
+ public FeedType getFeedType(Feed feed) throws InvalidFeedTypeException {
+ try {
+ return feedTypes.get(feed.getClass());
+ } catch (KeyNotMappedException e) {
+ throw new InvalidFeedTypeException(feed.getClass().getName());
+ }
+ }
+
+ public FeedDao getFeedDao(RestrictedFeed feed) throws InvalidFeedTypeException {
+ try {
+ return feedDaos.get(feed.getClass()).newInstance(feed);
+ } catch (InstantiationException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ } catch (KeyNotMappedException e) {
+ throw new InvalidFeedTypeException(feed.getClass().getName());
+ }
+ }
+
+ private void registerDao(Class<? extends FeedDao> daoClass) {
+ FeedType feedType = daoClass.getAnnotation(FeedType.class);
+
+ if (feedType == null) {
+ throw new IllegalArgumentException(
+ "Feed dao class: " + daoClass.getName() + " isn't annotated with @FeedType.");
+ }
+
+ Constructor<? extends FeedDao> constructor;
+ try {
+ constructor = daoClass.getConstructor(feedType.model());
+ } catch (NoSuchMethodException e) {
+ log.error("Feed dao class: " + daoClass.getName() + " doesn't define a one-arg constructor (" +
+ feedType.model().getName() + "), as the @FeedType annotation states.");
+ return;
+ }
+
+ log.info("Registering feed dao class: #0.", daoClass.getName());
+
+ feedDaos.put(feedType.model(), constructor);
+ feedTypes.put(feedType.model(), feedType);
+ }
+
+ public void handleClass(Class<?> toHandle) {
+ if (FeedDao.class.isAssignableFrom(toHandle)) {
+ //noinspection unchecked
+ registerDao((Class<? extends FeedDao>) toHandle);
+ } else {
+ log.error("Class " + toHandle.getName() + " is annotated with @FeedType but doesn't implement the " +
+ "FeedDao interface.");
+ }
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/feed/update/IndividualPostsFeedUpdate.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/feed/update/IndividualPostsFeedUpdate.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/feed/update/IndividualPostsFeedUpdate.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,76 @@
+package org.jboss.blog.session.feed.update;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.ScopeType;
+import org.jboss.blog.session.parser.ParserService;
+import org.jboss.blog.session.parser.ParserException;
+import org.jboss.blog.session.merge.MergeServiceBean;
+import org.jboss.blog.session.feed.lock.FeedsLocksBean;
+import org.jboss.blog.session.update.UpdateException;
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.feed.IndividualPostsFeed;
+import org.jboss.blog.model.feed.IndividualPostInfo;
+import org.jboss.blog.model.Post;
+
+import javax.persistence.EntityManager;
+import java.util.concurrent.locks.Lock;
+import java.util.List;
+import java.util.Date;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("individualPostsFeedUpdate")
+ at Scope(ScopeType.STATELESS)
+public class IndividualPostsFeedUpdate {
+ @In
+ private EntityManager entityManager;
+
+ @In
+ private ParserService parserService;
+
+ @In
+ private MergeServiceBean mergeService;
+
+ @In
+ private FeedsLocksBean feedsLocks;
+
+ public void update(IndividualPostsFeed feed) throws UpdateException {
+ // We update only posts from the last week.
+ Date thresholdDate = new Date(System.currentTimeMillis() - 7*24*60*60*1000);
+
+ Lock feedLock = feedsLocks.getLockForFeed(feed.getName());
+ feedLock.lock();
+ try {
+ //noinspection unchecked
+ List<IndividualPostInfo> postInfosToUpdate = entityManager
+ .createQuery(
+ "SELECT pi FROM IndividualPostInfo pi WHERE pi.feed = ?1 AND pi.post.published > ?2")
+ .setParameter(1, feed)
+ .setParameter(2, thresholdDate)
+ .getResultList();
+
+ for (IndividualPostInfo ipi : postInfosToUpdate) {
+ // Parsing the feed
+ Feed parsedFeed;
+ try {
+ parsedFeed = parserService.parse(ipi.getRemoteFeedAddress());
+ } catch (ParserException e) {
+ throw new UpdateException(e);
+ }
+
+ // Searching for the post
+ for (Post parsedPost : parsedFeed.getPosts()) {
+ if (parsedPost.compareTo(ipi.getPost()) == 0) {
+ mergeService.mergePosts(ipi.getPost(), parsedPost);
+ break;
+ }
+ }
+ }
+ } finally {
+ feedLock.unlock();
+ }
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/feed/update/RemoteFeedUpdate.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/feed/update/RemoteFeedUpdate.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/feed/update/RemoteFeedUpdate.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,50 @@
+package org.jboss.blog.session.feed.update;
+
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.feed.RemoteFeed;
+import org.jboss.blog.session.parser.ParserException;
+import org.jboss.blog.session.parser.ParserService;
+import org.jboss.blog.session.merge.MergeServiceBean;
+import org.jboss.blog.session.update.UpdateException;
+import org.jboss.blog.session.feed.lock.FeedsLocksBean;
+import org.jboss.blog.tools.PostFilterTools;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+
+import java.util.concurrent.locks.Lock;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("remoteFeedUpdate")
+ at Scope(ScopeType.STATELESS)
+public class RemoteFeedUpdate {
+ @In
+ private ParserService parserService;
+
+ @In
+ private MergeServiceBean mergeService;
+
+ @In
+ private FeedsLocksBean feedsLocks;
+
+ public void update(RemoteFeed feed) throws UpdateException {
+ Lock feedLock = feedsLocks.getLockForFeed(feed.getName());
+ feedLock.lock();
+ try {
+ Feed parsedFeed;
+ try {
+ parsedFeed = parserService.parse(feed.getRemoteLink());
+ } catch (ParserException e) {
+ throw new UpdateException(e);
+ }
+
+ mergeService.merge(feed, PostFilterTools.filterPostList(parsedFeed.getPosts(),
+ feed.getIncludeCategoryFilter()));
+ } finally {
+ feedLock.unlock();
+ }
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/group/GroupModBean.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/group/GroupModBean.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/group/GroupModBean.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,98 @@
+package org.jboss.blog.session.group;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.security.Restrict;
+import org.jboss.seam.faces.FacesMessages;
+import org.jboss.seam.core.Events;
+import org.jboss.seam.ScopeType;
+import org.jboss.blog.model.Group;
+import org.jboss.blog.service.GroupsService;
+import org.jboss.blog.tools.StringTools;
+
+import javax.persistence.EntityManager;
+import javax.faces.application.FacesMessage;
+import java.io.Serializable;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("groupMod")
+ at Scope(ScopeType.CONVERSATION)
+public class GroupModBean implements Serializable {
+ @In
+ private EntityManager entityManager;
+
+ @In
+ private FacesMessages facesMessages;
+
+ @In
+ private GroupsService groupsService;
+
+ private Group group;
+
+ public Group getGroup() {
+ if (group == null) {
+ group = new Group();
+ }
+
+ return group;
+ }
+
+ public void setGroup(Group group) {
+ this.group = group;
+ }
+
+ @Restrict("#{identity.hasPermission('group', 'add')}")
+ public void saveNew() {
+ group.setHeader(StringTools.fixHtml(group.getHeader()));
+
+ entityManager.persist(group);
+ entityManager.flush();
+
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, "blog.group.added", group.getDisplayName(),
+ group.getName());
+
+ Events.instance().raiseEvent("org.jboss.blog.group.added", group);
+ }
+
+ @Restrict("#{identity.hasPermission('group', 'edit', groupMod.group)}")
+ public void saveExisting() {
+ group.setHeader(StringTools.fixHtml(group.getHeader()));
+
+ entityManager.flush();
+
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, "blog.group.updated", group.getDisplayName(),
+ group.getName());
+
+ Events.instance().raiseEvent("org.jboss.blog.group.updated", group);
+ }
+
+ @Restrict("#{identity.hasPermission('group', 'delete', groupMod.group)}")
+ public void delete() {
+ if ((groupsService.acceptedFeeds(group).size() > 0) || (groupsService.unacceptedFeeds(group).size() > 0)) {
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, "blog.group.cannotdelete",
+ group.getDisplayName(), group.getName());
+
+ return;
+ }
+
+ Events.instance().raiseEvent("org.jboss.blog.group.before_delete", group);
+
+ entityManager.remove(group);
+
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, "blog.group.deleted", group.getDisplayName(),
+ group.getName());
+
+ Events.instance().raiseEvent("org.jboss.blog.group.deleted", group);
+ }
+
+ // Marker actions
+
+ public void add() { }
+
+ public void edit() { }
+
+ public void cancel() { }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/group/GroupsServiceImpl.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/group/GroupsServiceImpl.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/group/GroupsServiceImpl.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,60 @@
+package org.jboss.blog.session.group;
+
+import org.jboss.blog.service.GroupsService;
+import org.jboss.blog.model.Group;
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.ScopeType;
+
+import javax.persistence.EntityManager;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Scope(ScopeType.STATELESS)
+ at Name("groupsService")
+ at AutoCreate
+public class GroupsServiceImpl implements GroupsService {
+ @In
+ private EntityManager entityManager;
+
+ @SuppressWarnings("unchecked")
+ public List<Group> getAllGroups() {
+ return entityManager.createQuery("select group from Group group order by group.name")
+ .setHint("org.hibernate.cacheable", Boolean.TRUE).getResultList();
+ }
+
+ public List<Feed> acceptedFeeds(Group group) {
+ //noinspection unchecked
+ return entityManager
+ .createQuery("select feed from Feed feed where feed.group = ?1 and feed.accepted = true " +
+ "and (feed.restricted is null or feed.restricted = false)")
+ .setParameter(1, group).setHint("org.hibernate.cacheable", Boolean.TRUE).getResultList();
+ }
+
+ public List<Feed> unacceptedFeeds(Group group) {
+ //noinspection unchecked
+ return entityManager
+ .createQuery("select feed from Feed feed where feed.group = ?1 and not (feed.accepted = true) " +
+ "and (feed.restricted is null or feed.restricted = false)")
+ .setParameter(1, group).setHint("org.hibernate.cacheable", Boolean.TRUE).getResultList();
+ }
+
+ public List<Feed> restrictedFeeds(Group group) {
+ //noinspection unchecked
+ return entityManager
+ .createQuery("select feed from Feed feed where feed.group = ?1 and feed.restricted = true")
+ .setParameter(1, group).setHint("org.hibernate.cacheable", Boolean.TRUE).getResultList();
+ }
+
+ public List<Feed> allAcceptedFeeds(Group group) {
+ //noinspection unchecked
+ return entityManager
+ .createQuery("select feed from Feed feed where feed.group = ?1 and feed.accepted = true")
+ .setParameter(1, group).setHint("org.hibernate.cacheable", Boolean.TRUE).getResultList();
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/merge/FeedsServicePostsIterator.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/merge/FeedsServicePostsIterator.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/merge/FeedsServicePostsIterator.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,73 @@
+package org.jboss.blog.session.merge;
+
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.RestrictedPost;
+import org.jboss.blog.service.FeedsService;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class FeedsServicePostsIterator implements PostsIterator<RestrictedPost> {
+ private FeedsService feedsService;
+ private Feed feed;
+
+ private int chunkSize;
+ private int nextFrom;
+ private RestrictedPost current;
+
+ private Iterator<? extends RestrictedPost> iterator;
+ private int lastChunkSize;
+
+ public FeedsServicePostsIterator(FeedsService feedsService, Feed feed, int chunkSize) {
+ this.feedsService = feedsService;
+ this.feed = feed;
+ this.chunkSize = chunkSize;
+
+ nextFrom = 0;
+
+ readNextChunk();
+
+ if (iterator.hasNext()) {
+ current = iterator.next();
+ } else {
+ current = null;
+ }
+ }
+
+ private void readNextChunk() {
+ List<? extends RestrictedPost> posts = feedsService.getPosts(feed, nextFrom, nextFrom+chunkSize);
+ iterator = posts.iterator();
+ lastChunkSize = posts.size();
+ nextFrom += chunkSize;
+ }
+
+ public RestrictedPost getCurrent() {
+ return current;
+ }
+
+ public boolean finished() {
+ return current == null;
+ }
+
+ public RestrictedPost next() {
+ if (iterator.hasNext()) {
+ current = iterator.next();
+ } else {
+ if (lastChunkSize < chunkSize) {
+ current = null;
+ } else {
+ readNextChunk();
+ if (iterator.hasNext()) {
+ current = iterator.next();
+ } else {
+ current = null;
+ }
+ }
+ }
+
+ return current;
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/merge/ListPostsIterator.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/merge/ListPostsIterator.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/merge/ListPostsIterator.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,42 @@
+package org.jboss.blog.session.merge;
+
+import org.jboss.blog.model.RestrictedPost;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class ListPostsIterator<T extends RestrictedPost> implements PostsIterator<T> {
+ private Iterator<? extends T> iterator;
+ private T current;
+
+ public ListPostsIterator(List<? extends T> posts) {
+ iterator = posts.iterator();
+
+ if (iterator.hasNext()) {
+ current = iterator.next();
+ } else {
+ current = null;
+ }
+ }
+
+ public T getCurrent() {
+ return current;
+ }
+
+ public boolean finished() {
+ return current == null;
+ }
+
+ public T next() {
+ if (iterator.hasNext()) {
+ current = iterator.next();
+ } else {
+ current = null;
+ }
+
+ return current;
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/merge/MergeServiceBean.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/merge/MergeServiceBean.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/merge/MergeServiceBean.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,202 @@
+package org.jboss.blog.session.merge;
+
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.Post;
+import org.jboss.blog.model.Enclosure;
+import org.jboss.blog.model.Image;
+import org.jboss.blog.model.RestrictedPost;
+import org.jboss.blog.service.FeedsService;
+import org.jboss.blog.service.PostNotFoundException;
+import org.jboss.blog.service.LinkService;
+import org.jboss.blog.tools.GeneralTools;
+import org.jboss.blog.tools.StringTools;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.core.Events;
+import org.jboss.seam.annotations.*;
+import org.jboss.seam.log.Log;
+
+import javax.persistence.EntityManager;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("mergeService")
+ at AutoCreate
+ at Scope(ScopeType.STATELESS)
+public class MergeServiceBean {
+ @In
+ private FeedsService feedsService;
+
+ @In
+ private EntityManager entityManager;
+
+ @In
+ private TitleAsIdService titleAsIdService;
+
+ @In
+ private LinkService linkService;
+
+ @Logger
+ private Log log;
+
+ @In
+ private Events events;
+
+ public void savePost(Feed feed, Post post) {
+ // Preparing the post
+ post.setTitleAsId(titleAsIdService.generateTitleAsId(post.getTitle()));
+
+ if (StringTools.isEmpty(post.getLink())) {
+ post.setLink(linkService.generatePostLink(post));
+ }
+
+ post.setContent(StringTools.fixHtml(post.getContent()));
+
+ post.setFeed(feed);
+
+ log.debug("Saving post, feed: #0, post title: #1, post titleAsId: #2, published: #3.",
+ feed.getName(), post.getTitle(), post.getTitleAsId(), post.getPublished());
+
+ // Persisting
+ entityManager.persist(post);
+
+ for (Enclosure enc : post.getEnclosures()) {
+ entityManager.persist(enc);
+ }
+
+ for (Image image : post.getImages()) {
+ entityManager.persist(image);
+ }
+
+ entityManager.flush();
+
+ events.raiseEvent("org.jboss.blog.post.added", post);
+ }
+
+ private boolean checkNewPost(Post post, PostsIterator<RestrictedPost> mergeTo, PostsIterator<Post> mergeFrom) {
+ int currentPostSize = entityManager
+ .createQuery("select p from Post p where p.published = :p and p.title = :t")
+ .setParameter("p", post.getPublished())
+ .setParameter("t", post.getTitle())
+ .getResultList().size();
+
+ if (currentPostSize > 0) {
+ log.warn("Trying to save a duplicate post, merge to: #1, merge from: #2!", mergeTo.getCurrent(),
+ mergeFrom.getCurrent());
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Merges the given posts; checks for changes in:
+ * - author
+ * - content
+ * - link
+ * - dateModified
+ * - title
+ *
+ * The published date is assumed to be the same.
+ *
+ * Doesn't check for changes in:
+ * - categories.
+ *
+ * Also, in case of a title change, the titleAsId is not changed.
+ *
+ * @param mergeTo Post to which to merge the changes.
+ * @param mergeFrom Post from which to merge the changes.
+ */
+ public void mergePosts(Post mergeTo, Post mergeFrom) {
+ boolean changes = false;
+
+ if (!GeneralTools.objectsEqual(mergeTo.getAuthor(), mergeFrom.getAuthor())) {
+ log.debug("Post '#0' merge, changed author, new: '#1', old: '#2'.",
+ mergeTo.getTitleAsId(), mergeFrom.getAuthor(), mergeTo.getAuthor());
+ mergeTo.setAuthor(mergeFrom.getAuthor());
+ changes = true;
+ }
+
+ mergeFrom.setContent(StringTools.fixHtml(mergeFrom.getContent()));
+ if (!GeneralTools.objectsEqual(mergeTo.getContent(), mergeFrom.getContent())) {
+ log.debug("Post '#0' merge, changed content, new: '#1', old: '#2'.",
+ mergeTo.getTitleAsId(), mergeFrom.getContent(), mergeTo.getContent());
+ mergeTo.setContent(mergeFrom.getContent());
+ changes = true;
+ }
+
+ if ((mergeFrom.getLink() != null) && (!GeneralTools.objectsEqual(mergeTo.getLink(), mergeFrom.getLink()))) {
+ log.debug("Post '#0' merge, changed link, new: '#1', old: '#2'.",
+ mergeTo.getTitleAsId(), mergeFrom.getLink(), mergeTo.getLink());
+ mergeTo.setLink(mergeFrom.getLink());
+ changes = true;
+ }
+
+ if (mergeTo.getModified().getTime()/1000 != mergeFrom.getModified().getTime()/1000) {
+ log.debug("Post '#0' merge, changed modified date, new: '#1', old: '#2'.",
+ mergeTo.getTitleAsId(), mergeFrom.getModified().getTime(), mergeTo.getModified().getTime());
+ mergeTo.setModified(mergeFrom.getModified());
+ changes = true;
+ }
+
+ if (!GeneralTools.objectsEqual(mergeTo.getTitle(), mergeFrom.getTitle())) {
+ log.debug("Post '#0' merge, changed title, new: '#1', old: '#2'.",
+ mergeTo.getTitleAsId(), mergeFrom.getTitle(), mergeTo.getTitle());
+ mergeTo.setTitle(mergeFrom.getTitle());
+ changes = true;
+ }
+
+ if (changes) {
+ log.debug("Saving merged changes in post #0.", mergeTo.getTitleAsId());
+
+ entityManager.flush();
+
+ events.raiseEvent("org.jboss.blog.post.updated", mergeTo);
+ }
+ }
+
+ /**
+ *
+ * @param feed Feed, into which <code>posts</code> should be merged.
+ * @param posts A <b>sorted</b> list of posts, that should be merged to <code>feed</code>.
+ */
+ public void merge(Feed feed, List<Post> posts) {
+ PostsIterator<Post> mergeFrom = new ListPostsIterator<Post>(posts);
+ PostsIterator<RestrictedPost> mergeTo = new FeedsServicePostsIterator(feedsService, feed, posts.size()+1);
+
+ while (!mergeFrom.finished()) {
+ if (mergeTo.finished()) {
+ // no more current posts
+ if (checkNewPost(mergeFrom.getCurrent(), mergeTo, mergeFrom)) {
+ savePost(feed, mergeFrom.getCurrent());
+ }
+ mergeFrom.next();
+ } else {
+ int compare = mergeTo.getCurrent().compareTo(mergeFrom.getCurrent());
+
+ if (compare > 0) {
+ // mergeTo post is before mergeFrom post
+ if (checkNewPost(mergeFrom.getCurrent(), mergeTo, mergeFrom)) {
+ savePost(feed, mergeFrom.getCurrent());
+ }
+ mergeFrom.next();
+ } else if (compare == 0) {
+ try {
+ mergePosts(feedsService.getPost(mergeTo.getCurrent().getTitleAsId()), mergeFrom.getCurrent());
+ mergeTo.next();
+ mergeFrom.next();
+ } catch (PostNotFoundException e) {
+ mergeTo.next();
+ }
+ } else {
+ // mergeTo post is after mergeFrom post
+ // proceeding to the next mergeTo post (if exists)
+ mergeTo.next();
+ }
+ }
+ }
+
+ entityManager.flush();
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/merge/PostManager.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/merge/PostManager.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/merge/PostManager.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,40 @@
+package org.jboss.blog.session.merge;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.faces.FacesMessages;
+import org.jboss.seam.core.Events;
+import org.jboss.blog.model.Post;
+
+import javax.faces.application.FacesMessage;
+import javax.persistence.EntityManager;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("postManager")
+ at Scope(ScopeType.STATELESS)
+ at AutoCreate
+public class PostManager {
+ @In
+ private EntityManager entityManager;
+
+ @In
+ private FacesMessages facesMessages;
+
+ @In
+ private Events events;
+
+ public void deletePost(Post post) {
+ events.raiseEvent("org.jboss.blog.post.before_delete", post);
+
+ entityManager.remove(entityManager.merge(post));
+
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, "blog.post.deleted", post.getTitle());
+
+ events.raiseEvent("org.jboss.blog.post.deleted", post);
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/merge/PostsIterator.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/merge/PostsIterator.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/merge/PostsIterator.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,12 @@
+package org.jboss.blog.session.merge;
+
+import org.jboss.blog.model.RestrictedPost;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public interface PostsIterator<T extends RestrictedPost> {
+ public T getCurrent();
+ public T next();
+ public boolean finished();
+}
Added: feeds100P26/src/action/org/jboss/blog/session/merge/TitleAsIdService.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/merge/TitleAsIdService.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/merge/TitleAsIdService.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,8 @@
+package org.jboss.blog.session.merge;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public interface TitleAsIdService {
+ String generateTitleAsId(String title);
+}
Added: feeds100P26/src/action/org/jboss/blog/session/merge/TitleAsIdServiceBean.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/merge/TitleAsIdServiceBean.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/merge/TitleAsIdServiceBean.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,38 @@
+package org.jboss.blog.session.merge;
+
+import org.jboss.blog.tools.StringTools;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+
+import javax.persistence.EntityManager;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("titleAsIdService")
+ at Scope(ScopeType.STATELESS)
+ at AutoCreate
+public class TitleAsIdServiceBean implements TitleAsIdService {
+ @In
+ private EntityManager entityManager;
+
+ public String generateTitleAsId(String title) {
+ String candidate = StringTools.convertTitleToLink(title);
+ int nextCandidateNumber = 0;
+
+ while (true) {
+ int candidateCount = entityManager.createQuery("select post from Post post where post.titleAsId = ?1")
+ .setParameter(1, candidate).getResultList().size();
+
+ if (candidateCount > 0) {
+ candidate = StringTools.convertTitleToLink(title) + nextCandidateNumber;
+ nextCandidateNumber++;
+ } else {
+ return candidate;
+ }
+ }
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/parser/ParserException.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/parser/ParserException.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/parser/ParserException.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,21 @@
+package org.jboss.blog.session.parser;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class ParserException extends Exception {
+ public ParserException() {
+ }
+
+ public ParserException(String message) {
+ super(message);
+ }
+
+ public ParserException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public ParserException(Throwable cause) {
+ super(cause);
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/parser/ParserService.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/parser/ParserService.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/parser/ParserService.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,15 @@
+package org.jboss.blog.session.parser;
+
+import org.jboss.blog.model.feed.Feed;
+
+import javax.ejb.Local;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Local
+public interface ParserService {
+ void remove();
+
+ Feed parse(String link) throws ParserException;
+}
Added: feeds100P26/src/action/org/jboss/blog/session/parser/ParserServiceImpl.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/parser/ParserServiceImpl.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/parser/ParserServiceImpl.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,163 @@
+package org.jboss.blog.session.parser;
+
+import com.sun.syndication.feed.synd.*;
+import com.sun.syndication.io.FeedException;
+import com.sun.syndication.io.SyndFeedInput;
+import com.sun.syndication.io.XmlReader;
+import org.jboss.blog.model.Category;
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.Post;
+import org.jboss.blog.model.Enclosure;
+import org.jboss.blog.model.Image;
+import org.jboss.blog.model.configuration.Configuration;
+import org.jboss.blog.session.category.CategoryServiceBean;
+import org.jboss.blog.session.configuration.ConfigurationManager;
+import org.jboss.blog.tools.StringTools;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jdom.Element;
+import org.jdom.Attribute;
+import org.jdom.Content;
+
+import javax.ejb.Remove;
+import javax.ejb.Stateless;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.*;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Stateless
+ at Name("parserService")
+ at AutoCreate
+public class ParserServiceImpl implements ParserService {
+ @In
+ private CategoryServiceBean categoryService;
+
+ @In
+ private ConfigurationManager configurationManager;
+
+ private Image getImageFromForeignMarkup(Post post, List<Element> foreignMarkup) {
+ for (Element element : foreignMarkup) {
+ if ("image".equals(element.getName())) {
+ Attribute href = element.getAttribute("href");
+ if (href != null) {
+ return new Image(post, href.getValue());
+ }
+
+ Content content = element.getContent(0);
+ if (content != null) {
+ return new Image(post, content.getValue());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public Feed parse(String link) throws ParserException {
+ try {
+ SyndFeedInput input = new SyndFeedInput();
+
+ Configuration conf = configurationManager.getConfiguration();
+
+ URLConnection conn = new URL(link).openConnection();
+ conn.setReadTimeout(conf.getReadTimeout());
+ conn.setConnectTimeout(conf.getConnectionTimeout());
+ conn.connect();
+
+ SyndFeed syndFeed = input.build(new XmlReader(conn.getInputStream()));
+
+ Feed feed = new Feed();
+
+ feed.setAuthor(syndFeed.getAuthor());
+ feed.setDescription(syndFeed.getDescription());
+ feed.setLink(syndFeed.getLink());
+ feed.setTitle(syndFeed.getTitle());
+
+ List<Post> posts = new ArrayList<Post>();
+ feed.setPosts(posts);
+
+ if (syndFeed.getEntries() != null) {
+ for (Object entryObj : syndFeed.getEntries()) {
+ SyndEntry entry = (SyndEntry) entryObj;
+ Post post = new Post();
+
+ post.setFeed(feed);
+
+ post.setAuthor(StringTools.isEmpty(entry.getAuthor()) ? null : entry.getAuthor());
+
+ // Setting content
+ String longestContent = entry.getDescription() == null ? "" : entry.getDescription().getValue();
+
+ for (Object contentObj : entry.getContents()) {
+ SyndContent content = (SyndContent) contentObj;
+ String currentContent = content == null ? "" : content.getValue();
+
+ if (currentContent.length() > longestContent.length()) {
+ longestContent = currentContent;
+ }
+ }
+
+ post.setContent(longestContent);
+
+ // Setting categories
+ post.setCategories(new ArrayList<Category>());
+ for (Object categoryObj : entry.getCategories()) {
+ SyndCategory category = (SyndCategory) categoryObj;
+ post.getCategories().add(categoryService.getCategory(category.getName()));
+ }
+
+ // Setting enclosures
+ post.setEnclosures(new ArrayList<Enclosure>());
+ for (Object enclosureObj : entry.getEnclosures()) {
+ SyndEnclosure enclosure = (SyndEnclosure) enclosureObj;
+ post.getEnclosures().add(new Enclosure(post, enclosure.getUrl(),
+ enclosure.getLength(), enclosure.getType()));
+ }
+
+ // Setting images
+ post.setImages(new ArrayList<Image>());
+ //noinspection unchecked
+ Image postImage = getImageFromForeignMarkup(post, (List<Element>) entry.getForeignMarkup());
+ if (postImage != null) {
+ post.getImages().add(postImage);
+ }
+
+ // Setting the published date
+ Date publishedDate = entry.getPublishedDate();
+ if (publishedDate == null) {
+ publishedDate = entry.getUpdatedDate();
+ }
+
+ post.setPublished(publishedDate);
+
+ // And other properties
+ post.setTitle(entry.getTitle());
+ post.setModified(
+ entry.getUpdatedDate() == null ? post.getPublished() : entry.getUpdatedDate());
+ post.setLink(entry.getLink());
+
+ posts.add(post);
+ }
+ }
+
+ Collections.sort(posts);
+
+ return feed;
+ } catch (FeedException e) {
+ throw new ParserException(e);
+ } catch (MalformedURLException e) {
+ throw new ParserException(e);
+ } catch (IOException e) {
+ throw new ParserException(e);
+ }
+ }
+
+ @Remove
+ public void remove() { }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/scanner/AnnotationScanner.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/scanner/AnnotationScanner.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/scanner/AnnotationScanner.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,171 @@
+package org.jboss.blog.session.scanner;
+
+import org.jboss.seam.log.Logging;
+import org.jboss.seam.log.Log;
+
+import java.lang.annotation.Annotation;
+import java.util.Map;
+import java.util.Enumeration;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipEntry;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.DataInputStream;
+
+import javassist.bytecode.ClassFile;
+import javassist.bytecode.AnnotationsAttribute;
+
+/**
+ * Almost the same as {@link org.jboss.seam.deployment.Scanner}.
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class AnnotationScanner {
+ private static final Log log = Logging.getLog(AnnotationScanner.class);
+
+ private ClassLoader classLoader;
+ private Map<Class<? extends Annotation>, ClassHandler> handlers;
+
+ public AnnotationScanner(ClassLoader classLoader, Map<Class<? extends Annotation>, ClassHandler> handlers) {
+ this.classLoader = classLoader;
+ this.handlers = handlers;
+ }
+
+ private void addParentURLsOfResource(Set<String> urlPaths, String resourceName) throws IOException {
+ Enumeration<URL> urlEnum = classLoader.getResources(resourceName);
+ while (urlEnum.hasMoreElements()) {
+ String urlPath = urlEnum.nextElement().getFile();
+ urlPath = URLDecoder.decode(urlPath, "UTF-8");
+
+ if (urlPath.startsWith("file:")) {
+ // On windows urlpath looks like file:/C: on Linux file:/home
+ // substring(5) works for both
+ urlPath = urlPath.substring(5);
+ }
+
+ if (urlPath.indexOf('!') > 0) {
+ urlPath = urlPath.substring(0, urlPath.indexOf('!'));
+ } else {
+ File dirOrArchive = new File(urlPath);
+ if (resourceName != null && resourceName.lastIndexOf('/') > 0) {
+ dirOrArchive = dirOrArchive.getParentFile();
+ }
+
+ urlPath = dirOrArchive.getParent();
+ }
+
+ String dirOrArchiveName;
+ if (urlPath.lastIndexOf('/') != 0) {
+ dirOrArchiveName = urlPath.substring(urlPath.lastIndexOf('/') + 1);
+ } else {
+ dirOrArchiveName = urlPath;
+ }
+
+ if (dirOrArchiveName.contains("blog")) {
+ urlPaths.add(urlPath);
+ }
+ }
+ }
+
+ private Set<String> getUrlPaths() throws IOException {
+ Set<String> urlPaths = new HashSet<String>();
+
+ addParentURLsOfResource(urlPaths, "seam.properties");
+ addParentURLsOfResource(urlPaths, "META-INF/seam.properties");
+ addParentURLsOfResource(urlPaths, "META-INF/components.xml");
+
+ return urlPaths;
+ }
+
+ public void scan() {
+ Set<String> urlPaths;
+
+ try {
+ urlPaths = getUrlPaths();
+ } catch (IOException e) {
+ log.error("Error obtaining url paths.", e);
+ return;
+ }
+
+ for (String urlPath : urlPaths) {
+ try {
+ File file = new File(urlPath);
+
+ if (file.isDirectory()) {
+ scanDirectory(file, null);
+ } else {
+ scanArchive(file);
+ }
+ } catch (IOException e) {
+ log.error("Error while scanning url: " + urlPath, e);
+ }
+ }
+ }
+
+ private void scanArchive(File file) throws IOException {
+ ZipFile zipFile = new ZipFile(file);
+ Enumeration<? extends ZipEntry> zipEntries = zipFile.entries();
+
+ while (zipEntries.hasMoreElements()) {
+ ZipEntry zipEntry = zipEntries.nextElement();
+
+ scanItem(zipEntry.getName());
+ }
+ }
+
+ private void scanDirectory(File file, String relativePath) throws IOException {
+ for (File child : file.listFiles()) {
+ String newRealtivePath = relativePath == null ? child.getName() : relativePath + "/" + child.getName();
+
+ if (child.isDirectory()) {
+ scanDirectory(child, newRealtivePath);
+ } else {
+ scanItem(newRealtivePath);
+ }
+ }
+ }
+
+ private ClassFile getClassFile(String name) throws IOException {
+ InputStream stream = classLoader.getResourceAsStream(name);
+ DataInputStream dstream = new DataInputStream(stream);
+
+ try {
+ return new ClassFile(dstream);
+ } finally {
+ dstream.close();
+ stream.close();
+ }
+ }
+
+ private String filenameToClassname(String filename) {
+ return filename.substring(0, filename.lastIndexOf(".class")).replace('/', '.').replace('\\', '.');
+ }
+
+ private void scanItem(String name) throws IOException {
+ // TODO: remove the second part
+ if (name.endsWith(".class") && name.startsWith("org/jboss/blog/session/feed/dao")) {
+ ClassFile classFile = getClassFile(name);
+
+ AnnotationsAttribute visibleAnnotations = (AnnotationsAttribute)
+ classFile.getAttribute(AnnotationsAttribute.visibleTag);
+
+ if (visibleAnnotations == null) {
+ return;
+ }
+
+ for (Map.Entry<Class<? extends Annotation>, ClassHandler> entry : handlers.entrySet()) {
+ if (visibleAnnotations.getAnnotation(entry.getKey().getName()) != null) {
+ try {
+ entry.getValue().handleClass(classLoader.loadClass(filenameToClassname(name)));
+ } catch (ClassNotFoundException e) {
+ log.error("Error while loading class.", e);
+ }
+ }
+ }
+ }
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/scanner/ClassHandler.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/scanner/ClassHandler.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/scanner/ClassHandler.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,8 @@
+package org.jboss.blog.session.scanner;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public interface ClassHandler {
+ public void handleClass(Class<?> toHandle);
+}
Added: feeds100P26/src/action/org/jboss/blog/session/scanner/Init.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/scanner/Init.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/scanner/Init.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,34 @@
+package org.jboss.blog.session.scanner;
+
+import org.jboss.seam.annotations.*;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.core.Events;
+import org.jboss.blog.session.feed.type.FeedType;
+import org.jboss.blog.session.feed.type.FeedTypes;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.lang.annotation.Annotation;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("blogInit")
+ at Scope(ScopeType.APPLICATION)
+ at AutoCreate
+public class Init {
+ @In
+ private FeedTypes feedTypes;
+
+ @Observer("org.jboss.seam.postInitialization")
+ public void scanForBlogAnnotations() {
+ Map<Class<? extends Annotation>, ClassHandler> handlers =
+ new HashMap<Class<? extends Annotation>, ClassHandler>();
+
+ handlers.put(FeedType.class, feedTypes);
+
+ new AnnotationScanner(Thread.currentThread().getContextClassLoader(), handlers).scan();
+
+ Events.instance().raiseEvent("org.jboss.blog.postBlogInit");
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/search/PostSearchBean.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/search/PostSearchBean.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/search/PostSearchBean.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,164 @@
+package org.jboss.blog.session.search;
+
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.queryParser.MultiFieldQueryParser;
+import org.apache.lucene.queryParser.ParseException;
+import org.apache.lucene.search.Query;
+import org.hibernate.search.jpa.FullTextEntityManager;
+import org.hibernate.search.jpa.FullTextQuery;
+import org.jboss.blog.model.Post;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.security.Restrict;
+import org.jboss.seam.faces.FacesMessages;
+
+import javax.faces.application.FacesMessage;
+import java.util.ArrayList;
+import java.util.List;
+import java.io.Serializable;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("postSearch")
+ at Scope(ScopeType.CONVERSATION)
+public class PostSearchBean implements Serializable {
+ @In
+ private FullTextEntityManager entityManager;
+
+ @In
+ private FacesMessages facesMessages;
+
+ private String query;
+
+ private int from;
+
+ private List<Object[]> results;
+
+ private int resultsCount;
+
+ private static char[] LUCENE_SPECIAL =
+ { '\\', '+', '-', '&', '|', '!', '(', ')', '{', '}', '[', ']', '^', '\"', '~', ':' };
+
+ private static String[] ESCAPED_LUCENE_SPECIAL =
+ { "\\\\", "\\+", "\\-", "\\&", "\\|", "\\!", "\\(", "\\)", "\\{", "\\}", "\\[", "\\]", "\\^", "\\\"", "\\~", "\\:" };
+
+ public String getQuery() {
+ return query;
+ }
+
+ public void setQuery(String query) {
+ this.query = query;
+ }
+
+ private int getNumberOfResultsPerPage() {
+ return 10;
+ }
+
+ public int getFrom() {
+ return from;
+ }
+
+ public void setFrom(int from) {
+ this.from = from;
+ }
+
+ public boolean getShowNext() {
+ return getNextFrom() < resultsCount;
+ }
+
+ public boolean getShowPrevious() {
+ return from != 0;
+ }
+
+ public int getNextFrom() {
+ return from + getNumberOfResultsPerPage();
+ }
+
+ public int getPreviousFrom() {
+ return Math.max(0, from - getNumberOfResultsPerPage());
+ }
+
+ public int getResultsCount() {
+ return resultsCount;
+ }
+
+ public List<Object[]> getResults() {
+ return results;
+ }
+
+ private String replaceAll(String where, char what, String replacement) {
+ StringBuilder sb = new StringBuilder();
+
+ for (int i=0; i<where.length(); i++) {
+ char whereAtI = where.charAt(i);
+ if (whereAtI == what) {
+ sb.append(replacement);
+ } else {
+ sb.append(whereAtI);
+ }
+ }
+
+ return sb.toString();
+ }
+
+ private String escapeQuery(String query) {
+ for (int i=0; i<LUCENE_SPECIAL.length; i++) {
+ query = replaceAll(query, LUCENE_SPECIAL[i], ESCAPED_LUCENE_SPECIAL[i]);
+ }
+ return query;
+ }
+
+ private FullTextQuery getFullTextQuery() throws ParseException {
+ MultiFieldQueryParser parser = new MultiFieldQueryParser(
+ new String[]{ "title", "content", "author" },
+ new StandardAnalyzer());
+ Query luceneQuery = parser.parse(escapeQuery(getQuery()));
+
+ FullTextQuery fullTextQuery = entityManager.createFullTextQuery(luceneQuery, Post.class);
+ fullTextQuery.enableFullTextFilter("unrestrictedFeedFilter");
+ fullTextQuery.setProjection(FullTextQuery.SCORE, FullTextQuery.THIS);
+
+ return fullTextQuery;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void search() {
+ if (query == null || "".equals(query.trim())) {
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, "blog.search.emptyquery");
+ results = new ArrayList<Object[]>();
+ resultsCount = 0;
+ return;
+ }
+
+ FullTextQuery fullTextQuery;
+ try {
+ fullTextQuery = getFullTextQuery();
+ } catch (ParseException e) {
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_ERROR, "blog.search.exception",
+ e.getMessage());
+ results = new ArrayList<Object[]>();
+ resultsCount = 0;
+ return;
+ }
+
+ results = fullTextQuery.setFirstResult(getFrom()).setMaxResults(getNumberOfResultsPerPage())
+ .getResultList();
+ resultsCount = fullTextQuery.getResultSize();
+ }
+
+ public String formatScore(float f) {
+ return String.format("%.2f", f*100);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Restrict("#{identity.hasPermission('admin', null)}")
+ public void reindex() {
+ List<Post> posts = entityManager.createQuery("select post from Post post").getResultList();
+ for (Post post : posts) {
+ entityManager.index(post);
+ }
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/search/SearchReindexObserver.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/search/SearchReindexObserver.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/search/SearchReindexObserver.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,30 @@
+package org.jboss.blog.session.search;
+
+import org.jboss.seam.annotations.Observer;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.Post;
+import org.hibernate.search.jpa.FullTextEntityManager;
+
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("searchReindexObserver")
+public class SearchReindexObserver {
+ @In
+ private FullTextEntityManager entityManager;
+
+ @Observer({"org.jboss.blog.feed.updated"})
+ public void feedUpdated(Feed feed) {
+ //noinspection unchecked
+ List<Post> posts = entityManager.createQuery("select post from Post post where post.feed = ?1")
+ .setParameter(1, feed).getResultList();
+
+ for (Post post : posts) {
+ entityManager.index(post);
+ }
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/security/Authenticator.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/security/Authenticator.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/security/Authenticator.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,60 @@
+package org.jboss.blog.session.security;
+
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.blog.model.security.SecurityUser;
+import org.jboss.blog.model.security.SecurityGroup;
+import org.jboss.blog.model.security.SecurityMapping;
+import org.jboss.blog.session.security.external.ExternalSecurityService;
+
+import java.util.List;
+
+ at Name("authenticator")
+ at AutoCreate
+public class Authenticator {
+ @In
+ private FeedsIdentity identity;
+
+ @In
+ private ExternalSecurityService externalSecurityService;
+
+ private void addFeedRolesFromMappings(List<SecurityMapping> mappings) {
+ if (mappings != null) {
+ for (SecurityMapping mapping : mappings) {
+ identity.addFeedsRole(mapping.getRole(), mapping.getIdForRole());
+ }
+ }
+ }
+
+ private void flushRoles(SecurityUser user) {
+ identity.setSecurityUser(user);
+
+ identity.removeAllFeedsRoles();
+
+ if (user != null) {
+ addFeedRolesFromMappings(user.getMappings());
+ for (SecurityGroup securityGroup : externalSecurityService.getGroupsOfUser(user)) {
+ addFeedRolesFromMappings(securityGroup.getMappings());
+ }
+ }
+ }
+
+ public void flushRoles() {
+ flushRoles(externalSecurityService.getUnrestrictedSecurityUser(identity.getSecurityUser()));
+ }
+
+ public boolean authenticate() {
+ SecurityUser user;
+
+ try {
+ user = externalSecurityService.authenticate(identity.getUsername(), identity.getPassword());
+ } catch (InvalidLoginException e) {
+ return false;
+ }
+
+ flushRoles(user);
+
+ return true;
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/security/FeedsCombinedRole.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/security/FeedsCombinedRole.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/security/FeedsCombinedRole.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,43 @@
+package org.jboss.blog.session.security;
+
+import org.jboss.blog.model.security.FeedsSecurityRole;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class FeedsCombinedRole {
+ private FeedsSecurityRole role;
+ private Integer id;
+
+ public FeedsCombinedRole(FeedsSecurityRole role, Integer id) {
+ this.role = role;
+ this.id = id;
+ }
+
+ public FeedsSecurityRole getRole() {
+ return role;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof FeedsCombinedRole)) return false;
+
+ FeedsCombinedRole that = (FeedsCombinedRole) o;
+
+ if (id != null ? !id.equals(that.id) : that.id != null) return false;
+ if (role != that.role) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ int result;
+ result = (role != null ? role.hashCode() : 0);
+ result = 31 * result + (id != null ? id.hashCode() : 0);
+ return result;
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/security/FeedsIdentity.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/security/FeedsIdentity.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/security/FeedsIdentity.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,135 @@
+package org.jboss.blog.session.security;
+
+import org.jboss.seam.security.RuleBasedIdentity;
+import org.jboss.seam.annotations.*;
+import static org.jboss.seam.annotations.Install.APPLICATION;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+import static org.jboss.seam.ScopeType.SESSION;
+import org.jboss.blog.model.security.FeedsSecurityRole;
+import org.jboss.blog.model.security.SecurityUser;
+import org.drools.StatefulSession;
+import org.drools.FactHandle;
+import org.drools.base.ClassObjectFilter;
+
+import java.util.Iterator;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("org.jboss.seam.security.identity")
+ at Scope(SESSION)
+ at BypassInterceptors
+ at Install(precedence = APPLICATION)
+ at Startup
+ at AutoCreate
+public class FeedsIdentity extends RuleBasedIdentity {
+ private SecurityUser securityUser;
+ private boolean pretendedLogin;
+
+ public SecurityUser getSecurityUser() {
+ return securityUser;
+ }
+
+ public void setSecurityUser(SecurityUser securityUser) {
+ this.securityUser = securityUser;
+ }
+
+ public boolean addFeedsRole(FeedsSecurityRole role) {
+ return addFeedsRole(role, null);
+ }
+
+ public boolean addFeedsRole(FeedsSecurityRole role, Integer id) {
+ StatefulSession securityContext = getSecurityContext();
+
+ if (securityContext != null) {
+ securityContext.insert(new FeedsCombinedRole(role, id));
+ securityContext.fireAllRules();
+ return true;
+ }
+
+ return false;
+ }
+
+ public void removeAllFeedsRoles() {
+ StatefulSession securityContext = getSecurityContext();
+
+ if (securityContext != null) {
+ //noinspection unchecked
+ Iterator<FeedsCombinedRole> iter = securityContext.iterateObjects(
+ new ClassObjectFilter(FeedsCombinedRole.class));
+ while (iter.hasNext()) {
+ FeedsCombinedRole r = iter.next();
+ FactHandle fh = getSecurityContext().getFactHandle(r);
+ getSecurityContext().retract(fh);
+ }
+
+ securityContext.fireAllRules();
+ }
+ }
+
+ public void removeFeedsRole(FeedsSecurityRole role) {
+ removeFeedsRole(role, null);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void removeFeedsRole(FeedsSecurityRole role, Integer id) {
+ StatefulSession securityContext = getSecurityContext();
+
+ FeedsCombinedRole fcr = new FeedsCombinedRole(role, id);
+
+ if (securityContext != null) {
+ Iterator<FeedsCombinedRole> iter = securityContext.iterateObjects(
+ new ClassObjectFilter(FeedsCombinedRole.class));
+ while (iter.hasNext()) {
+ FeedsCombinedRole r = iter.next();
+ if (r.equals(fcr)) {
+ FactHandle fh = getSecurityContext().getFactHandle(r);
+ getSecurityContext().retract(fh);
+ break;
+ }
+ }
+
+ securityContext.fireAllRules();
+ }
+ }
+
+ public boolean hasPermission(String s, String s1, Object... objects) {
+ int arraySize = 0;
+ for (Object object : objects) {
+ if (object != null) {
+ arraySize++;
+ }
+ }
+
+ Object[] newObjects = new Object[arraySize];
+ int arrayIndex = 0;
+ for (Object object : objects) {
+ if (object != null) {
+ newObjects[arrayIndex++] = object;
+ }
+ }
+
+ return super.hasPermission(s, s1, newObjects);
+ }
+
+ public boolean isLoggedIn() {
+ if (pretendedLogin) {
+ return true;
+ } else {
+ return super.isLoggedIn();
+ }
+ }
+
+ public void loginAsAdmin() {
+ preAuthenticate();
+ pretendedLogin = true;
+ postAuthenticate();
+
+ addFeedsRole(FeedsSecurityRole.ADMIN);
+ }
+
+ public void loginAs(SecurityUser su) {
+ setSecurityUser(su);
+ pretendedLogin = true;
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/security/InvalidLoginException.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/security/InvalidLoginException.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/security/InvalidLoginException.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,7 @@
+package org.jboss.blog.session.security;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class InvalidLoginException extends Exception {
+}
Added: feeds100P26/src/action/org/jboss/blog/session/security/RestrictedKeyGenerator.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/security/RestrictedKeyGenerator.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/security/RestrictedKeyGenerator.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,49 @@
+package org.jboss.blog.session.security;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.ScopeType;
+
+import javax.persistence.EntityManager;
+import java.util.Random;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("restrictedKeyGenerator")
+ at Scope(ScopeType.STATELESS)
+ at AutoCreate
+public class RestrictedKeyGenerator {
+ @In
+ private EntityManager entityManager;
+
+ private boolean keyValid(String key) {
+ if (key.length() < 8) {
+ return false;
+ }
+
+ List results = entityManager.createQuery("select su from SecurityUser su where su.restrictedKey = ?1")
+ .setParameter(1, key).getResultList();
+
+ if (results.size() == 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public String generate() {
+ Random random = new Random();
+
+ String key;
+ do {
+ key = Long.toString(Math.abs(random.nextLong()), 36);
+ } while (!keyValid(key));
+
+ return key;
+ }
+}
+
Added: feeds100P26/src/action/org/jboss/blog/session/security/SecurityGroupConverter.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/security/SecurityGroupConverter.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/security/SecurityGroupConverter.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,28 @@
+package org.jboss.blog.session.security;
+
+import org.jboss.blog.model.security.RestrictedSecurityGroup;
+import org.jboss.blog.model.security.SecurityGroup;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Transactional;
+import org.jboss.seam.annotations.faces.Converter;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("securityGroupConverter")
+ at BypassInterceptors
+ at Converter
+public class SecurityGroupConverter implements javax.faces.convert.Converter {
+ @Transactional
+ public Object getAsObject(FacesContext context, UIComponent cmp, String value) {
+ return new SecurityGroup(null, value);
+ }
+
+ public String getAsString(FacesContext context, UIComponent cmp, Object value) {
+ return ((RestrictedSecurityGroup) value).getExternalId();
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/security/SecurityModBean.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/security/SecurityModBean.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/security/SecurityModBean.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,218 @@
+package org.jboss.blog.session.security;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.security.Restrict;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.faces.FacesMessages;
+import org.jboss.blog.model.security.*;
+import org.jboss.blog.model.Group;
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.session.security.external.ExternalSecurityService;
+
+import javax.faces.application.FacesMessage;
+import java.util.List;
+import java.io.Serializable;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("securityMod")
+ at Scope(ScopeType.CONVERSATION)
+ at AutoCreate
+public class SecurityModBean implements Serializable {
+ @In
+ private ExternalSecurityService externalSecurityService;
+
+ @In
+ private FacesMessages facesMessages;
+
+ private RestrictedSecurityGroup restrictedSecurityGroup;
+ private RestrictedSecurityUser restrictedSecurityUser;
+ private Group group;
+ private Feed feed;
+ private FeedsSecurityRole role;
+
+ public RestrictedSecurityGroup getRestrictedSecurityGroup() {
+ return restrictedSecurityGroup;
+ }
+
+ public void setRestrictedSecurityGroup(RestrictedSecurityGroup restrictedSecurityGroup) {
+ this.restrictedSecurityGroup = restrictedSecurityGroup;
+ }
+
+ public RestrictedSecurityUser getRestrictedSecurityUser() {
+ return restrictedSecurityUser;
+ }
+
+ public void setRestrictedSecurityUser(RestrictedSecurityUser restrictedSecurityUser) {
+ this.restrictedSecurityUser = restrictedSecurityUser;
+ }
+
+ public Group getGroup() {
+ return group;
+ }
+
+ public void setGroup(Group group) {
+ this.group = group;
+ }
+
+ public Feed getFeed() {
+ return feed;
+ }
+
+ public void setFeed(Feed feed) {
+ this.feed = feed;
+ }
+
+ public FeedsSecurityRole getRole() {
+ return role;
+ }
+
+ public void setRole(FeedsSecurityRole role) {
+ this.role = role;
+ }
+
+ public List<SecurityGroup> getAdministratorGroups() {
+ return externalSecurityService.getMapping(FeedsSecurityRole.ADMIN, null).getGroups();
+ }
+
+ public List<SecurityGroup> getGroupAdministratorGroups(Group group) {
+ return externalSecurityService.getMapping(FeedsSecurityRole.GROUP_ADMIN, group.getId()).getGroups();
+ }
+
+ public List<SecurityGroup> getFeedAdministratorGroups(Feed feed) {
+ return externalSecurityService.getMapping(FeedsSecurityRole.FEED_ADMIN, feed.getId()).getGroups();
+ }
+
+ public List<SecurityGroup> getFeedViewersGroups(Feed feed) {
+ return externalSecurityService.getMapping(FeedsSecurityRole.VIEW, feed.getId()).getGroups();
+ }
+
+ public List<SecurityUser> getAdministratorUsers() {
+ return externalSecurityService.getMapping(FeedsSecurityRole.ADMIN, null).getUsers();
+ }
+
+ public List<SecurityUser> getGroupAdministratorUsers(Group group) {
+ return externalSecurityService.getMapping(FeedsSecurityRole.GROUP_ADMIN, group.getId()).getUsers();
+ }
+
+ public List<SecurityUser> getFeedAdministratorUsers(Feed feed) {
+ return externalSecurityService.getMapping(FeedsSecurityRole.FEED_ADMIN, feed.getId()).getUsers();
+ }
+
+ public List<SecurityUser> getFeedViewersUsers(Feed feed) {
+ return externalSecurityService.getMapping(FeedsSecurityRole.VIEW, feed.getId()).getUsers();
+ }
+
+ private SecurityMapping getMapping() {
+ Integer idForRole;
+
+ switch (getRole()) {
+ case GROUP_ADMIN: idForRole = getGroup().getId(); break;
+ case FEED_ADMIN: idForRole = getFeed().getId(); break;
+ case VIEW: idForRole = getFeed().getId(); break;
+ default: idForRole = null;
+ }
+
+ return externalSecurityService.getMapping(getRole(), idForRole);
+ }
+
+ public void addSecurityGroupAsSuperUser() {
+ SecurityGroup sg = externalSecurityService.getUnrestrictedSecurityGroup(getRestrictedSecurityGroup());
+ SecurityMapping mapping = getMapping();
+
+ if (!mapping.getGroups().contains(sg)) {
+ mapping.getGroups().add(sg);
+ }
+
+ String bundleId;
+ Object param = null;
+ switch (getRole()) {
+ case ADMIN: bundleId = "blog.security.group.admin.added"; break;
+ case GROUP_ADMIN: bundleId = "blog.security.group.group.added"; param = getGroup().getDisplayName(); break;
+ case FEED_ADMIN: bundleId = "blog.security.group.feed.added"; param = getFeed().getName(); break;
+ case VIEW: bundleId = "blog.security.group.feedview.added"; param = getFeed().getName(); break;
+ default: return;
+ }
+
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, bundleId,
+ externalSecurityService.getDisplayName(sg), param);
+ }
+
+ @Restrict("#{identity.hasPermission('security_group', 'add', securityMod.role, securityMod.group, securityMod.feed)}")
+ public void addSecurityGroup() {
+ addSecurityGroupAsSuperUser();
+ }
+
+ @Restrict("#{identity.hasPermission('security_group', 'delete', securityMod.role, securityMod.group, securityMod.feed)}")
+ public void deleteSecurityGroup() {
+ SecurityGroup sg = externalSecurityService.getUnrestrictedSecurityGroup(getRestrictedSecurityGroup());
+ SecurityMapping mapping = getMapping();
+
+ mapping.getGroups().remove(sg);
+
+ String bundleId;
+ Object param = null;
+ switch (getRole()) {
+ case ADMIN: bundleId = "blog.security.group.admin.deleted"; break;
+ case GROUP_ADMIN: bundleId = "blog.security.group.group.deleted"; param = getGroup().getDisplayName(); break;
+ case FEED_ADMIN: bundleId = "blog.security.group.feed.deleted"; param = getFeed().getName(); break;
+ case VIEW: bundleId = "blog.security.group.feedview.deleted"; param = getFeed().getName(); break;
+ default: return;
+ }
+
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, bundleId,
+ externalSecurityService.getDisplayName(sg), param);
+ }
+
+ public void addSecurityUserAsSuperUser() {
+ SecurityUser su = externalSecurityService.getUnrestrictedSecurityUser(getRestrictedSecurityUser());
+ SecurityMapping mapping = getMapping();
+
+ if (!mapping.getUsers().contains(su)) {
+ mapping.getUsers().add(su);
+ }
+
+ String bundleId;
+ Object param = null;
+ switch (getRole()) {
+ case ADMIN: bundleId = "blog.security.user.admin.added"; break;
+ case GROUP_ADMIN: bundleId = "blog.security.user.group.added"; param = getGroup().getDisplayName(); break;
+ case FEED_ADMIN: bundleId = "blog.security.user.feed.added"; param = getFeed().getName(); break;
+ case VIEW: bundleId = "blog.security.user.feedview.added"; param = getFeed().getName(); break;
+ default: return;
+ }
+
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, bundleId,
+ externalSecurityService.getDisplayName(su), param);
+ }
+
+ @Restrict("#{identity.hasPermission('security_user', 'add', securityMod.role, securityMod.group, securityMod.feed)}")
+ public void addSecurityUser() {
+ addSecurityUserAsSuperUser();
+ }
+
+ @Restrict("#{identity.hasPermission('security_user', 'delete', securityMod.role, securityMod.group, securityMod.feed)}")
+ public void deleteSecurityUser() {
+ SecurityUser su = externalSecurityService.getUnrestrictedSecurityUser(getRestrictedSecurityUser());
+ SecurityMapping mapping = getMapping();
+
+ mapping.getUsers().remove(su);
+
+ String bundleId;
+ Object param = null;
+ switch (getRole()) {
+ case ADMIN: bundleId = "blog.security.user.admin.deleted"; break;
+ case GROUP_ADMIN: bundleId = "blog.security.user.group.deleted"; param = getGroup().getDisplayName(); break;
+ case FEED_ADMIN: bundleId = "blog.security.user.feed.deleted"; param = getFeed().getName(); break;
+ case VIEW: bundleId = "blog.security.user.feedview.deleted"; param = getFeed().getName(); break;
+ default: return;
+ }
+
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, bundleId,
+ externalSecurityService.getDisplayName(su), param);
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/security/SecurityObserver.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/security/SecurityObserver.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/security/SecurityObserver.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,84 @@
+package org.jboss.blog.session.security;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Observer;
+import org.jboss.seam.annotations.In;
+import org.jboss.blog.model.Group;
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.security.FeedsSecurityRole;
+import org.jboss.blog.model.security.SecurityMapping;
+
+import javax.persistence.EntityManager;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("securityObserver")
+public class SecurityObserver {
+ @In
+ private FeedsIdentity identity;
+
+ @In
+ private EntityManager entityManager;
+
+ @In
+ private SecurityModBean securityMod;
+
+ @In
+ private Authenticator authenticator;
+
+ @Observer({"org.jboss.blog.group.updated"})
+ public void groupUpdated(Group group) { }
+
+ @Observer({"org.jboss.blog.group.added"})
+ public void groupAdded(Group group) {
+ if (!identity.hasPermission("group", "edit", group)) {
+ securityMod.setRole(FeedsSecurityRole.GROUP_ADMIN);
+ securityMod.setGroup(group);
+ securityMod.setRestrictedSecurityUser(identity.getSecurityUser());
+
+ securityMod.addSecurityUserAsSuperUser();
+
+ entityManager.flush();
+
+ authenticator.flushRoles();
+ }
+ }
+
+ @Observer({"org.jboss.blog.group.deleted"})
+ public void groupDeleted(Group group) {
+ //noinspection unchecked
+ List<SecurityMapping> mappings =
+ entityManager.createQuery("select sm from SecurityMapping sm where sm.idForRole = ?1 and sm.role = ?2")
+ .setParameter(1, group.getId()).setParameter(2, FeedsSecurityRole.GROUP_ADMIN)
+ .getResultList();
+
+ for (SecurityMapping mapping : mappings) {
+ entityManager.remove(mapping);
+ }
+
+ entityManager.flush();
+ }
+
+ @Observer({"org.jboss.blog.feed.updated"})
+ public void feedUpdated(Feed feed) { }
+
+ @Observer({"org.jboss.blog.feed.added"})
+ public void feedAdded(Feed feed) { }
+
+ @Observer({"org.jboss.blog.feed.deleted"})
+ public void feedDeleted(Feed feed) {
+ //noinspection unchecked
+ List<SecurityMapping> mappings =
+ entityManager.createQuery("select sm from SecurityMapping sm where sm.idForRole = ?1 and sm.role = ?2")
+ .setParameter(1, feed.getId()).setParameter(2, FeedsSecurityRole.FEED_ADMIN)
+ .getResultList();
+
+ for (SecurityMapping mapping : mappings) {
+ entityManager.remove(mapping);
+ }
+
+ entityManager.flush();
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/security/SecurityRoleConverter.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/security/SecurityRoleConverter.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/security/SecurityRoleConverter.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,27 @@
+package org.jboss.blog.session.security;
+
+import org.jboss.blog.model.security.FeedsSecurityRole;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Transactional;
+import org.jboss.seam.annotations.faces.Converter;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("securityRoleConverter")
+ at BypassInterceptors
+ at Converter
+public class SecurityRoleConverter implements javax.faces.convert.Converter {
+ @Transactional
+ public Object getAsObject(FacesContext context, UIComponent cmp, String value) {
+ return FeedsSecurityRole.valueOf(value);
+ }
+
+ public String getAsString(FacesContext context, UIComponent cmp, Object value) {
+ return value.toString();
+ }
+}
\ No newline at end of file
Added: feeds100P26/src/action/org/jboss/blog/session/security/SecurityUserConverter.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/security/SecurityUserConverter.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/security/SecurityUserConverter.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,28 @@
+package org.jboss.blog.session.security;
+
+import org.jboss.blog.model.security.SecurityUser;
+import org.jboss.blog.model.security.RestrictedSecurityUser;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Transactional;
+import org.jboss.seam.annotations.faces.Converter;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("securityUserConverter")
+ at BypassInterceptors
+ at Converter
+public class SecurityUserConverter implements javax.faces.convert.Converter {
+ @Transactional
+ public Object getAsObject(FacesContext context, UIComponent cmp, String value) {
+ return new SecurityUser(null, value);
+ }
+
+ public String getAsString(FacesContext context, UIComponent cmp, Object value) {
+ return ((RestrictedSecurityUser) value).getExternalId();
+ }
+}
\ No newline at end of file
Added: feeds100P26/src/action/org/jboss/blog/session/security/SecurityUserKeys.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/security/SecurityUserKeys.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/security/SecurityUserKeys.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,62 @@
+package org.jboss.blog.session.security;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.ScopeType;
+import org.jboss.blog.tools.StringTools;
+import org.jboss.blog.model.security.SecurityUser;
+
+import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("securityUserKeys")
+ at Scope(ScopeType.STATELESS)
+ at AutoCreate
+public class SecurityUserKeys {
+ @In
+ private FeedsIdentity identity;
+
+ @In
+ private RestrictedKeyGenerator restrictedKeyGenerator;
+
+ @In
+ private EntityManager entityManager;
+
+ public void generateKeyForCurrentUser() {
+ SecurityUser su = identity.getSecurityUser();
+ su = entityManager.merge(su);
+
+ su.setRestrictedKey(restrictedKeyGenerator.generate());
+ identity.setSecurityUser(su);
+
+ entityManager.flush();
+ }
+
+ public String getKeyOfCurrentUser() {
+ if (identity.getSecurityUser() == null) {
+ return null;
+ }
+
+ if (StringTools.isEmpty(identity.getSecurityUser().getRestrictedKey())) {
+ generateKeyForCurrentUser();
+ }
+
+ return identity.getSecurityUser().getRestrictedKey();
+ }
+
+ public SecurityUser seachForSecurityUserByKey(String key) {
+ try {
+ return (SecurityUser) entityManager
+ .createQuery("select su from SecurityUser su where su.restrictedKey = ?1")
+ .setParameter(1, key)
+ .getSingleResult();
+ } catch (NoResultException e) {
+ return null;
+ }
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/security/SecurityUserSelectBean.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/security/SecurityUserSelectBean.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/security/SecurityUserSelectBean.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,85 @@
+package org.jboss.blog.session.security;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.annotations.In;
+import org.jboss.blog.session.security.external.ExternalSecurityService;
+import org.jboss.blog.model.security.RestrictedSecurityUser;
+import org.jboss.blog.tools.StringTools;
+import org.jboss.blog.tools.GeneralTools;
+
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("securityUserSelect")
+ at AutoCreate
+public class SecurityUserSelectBean {
+ private int from;
+
+ private String filter;
+
+ private List<? extends RestrictedSecurityUser> realUsers;
+ private List<? extends RestrictedSecurityUser> users;
+
+ @In
+ private ExternalSecurityService externalSecurityService;
+
+ public int getFrom() {
+ return from;
+ }
+
+ public void setFrom(int from) {
+ this.from = from;
+ }
+
+ public String getFilter() {
+ return filter;
+ }
+
+ public void setFilter(String filter) {
+ this.filter = filter;
+ }
+
+ public int getNumberOfUsersOnPage() {
+ return 25;
+ }
+
+ private void initRealUsers() {
+ if (realUsers == null) {
+ if (StringTools.isEmpty(filter)) {
+ realUsers = externalSecurityService.getUsers(from, getNumberOfUsersOnPage()+1);
+ } else {
+ realUsers = externalSecurityService.getUsers(filter, from, getNumberOfUsersOnPage()+1);
+ }
+ }
+ }
+
+ public List<? extends RestrictedSecurityUser> getUsers() {
+ if (users == null) {
+ initRealUsers();
+ users = GeneralTools.subList(realUsers, 0, getNumberOfUsersOnPage());
+ }
+
+ return users;
+ }
+
+ public boolean getShowPrevious() {
+ return from != 0;
+ }
+
+ public boolean getShowNext() {
+ initRealUsers();
+ return realUsers.size() == getNumberOfUsersOnPage()+1;
+ }
+
+ public int getPreviousFrom() {
+ return Math.max(0, from - getNumberOfUsersOnPage());
+ }
+
+ public int getNextFrom() {
+ return from + getNumberOfUsersOnPage();
+ }
+
+}
Added: feeds100P26/src/action/org/jboss/blog/session/security/external/AbstractExternalSecurityService.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/security/external/AbstractExternalSecurityService.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/security/external/AbstractExternalSecurityService.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,76 @@
+package org.jboss.blog.session.security.external;
+
+import org.jboss.blog.model.security.*;
+
+import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
+import java.util.ArrayList;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public abstract class AbstractExternalSecurityService implements ExternalSecurityService {
+ protected abstract EntityManager getEntityManager();
+
+ public SecurityGroup getUnrestrictedSecurityGroup(RestrictedSecurityGroup securityGroup) {
+ try {
+ SecurityGroup entitySg = (SecurityGroup) getEntityManager().createQuery(
+ "select sg from SecurityGroup sg where sg.externalId = ?1")
+ .setParameter(1, securityGroup.getExternalId()).getSingleResult();
+ entitySg.setRealGroup(securityGroup.getRealGroup());
+
+ return entitySg;
+ } catch (NoResultException e) {
+ SecurityGroup sg = new SecurityGroup();
+ sg.setExternalId(securityGroup.getExternalId());
+ sg.setRealGroup(securityGroup.getRealGroup());
+
+ getEntityManager().persist(sg);
+
+ return sg;
+ }
+ }
+
+ public SecurityUser getUnrestrictedSecurityUser(RestrictedSecurityUser securityUser) {
+ try {
+ SecurityUser entitySu = (SecurityUser) getEntityManager().createQuery(
+ "select su from SecurityUser su where su.externalId = ?1")
+ .setParameter(1, securityUser.getExternalId()).getSingleResult();
+ entitySu.setRealUser(securityUser.getRealUser());
+
+ return entitySu;
+ } catch (NoResultException e) {
+ SecurityUser su = new SecurityUser();
+ su.setExternalId(securityUser.getExternalId());
+ su.setRealUser(securityUser.getRealUser());
+
+ getEntityManager().persist(su);
+
+ return su;
+ }
+ }
+
+ public SecurityMapping getMapping(FeedsSecurityRole role, Integer idForRole) {
+ try {
+ if (idForRole == null) {
+ return (SecurityMapping) getEntityManager().createQuery(
+ "select mapping from SecurityMapping mapping where mapping.role = ?1")
+ .setParameter(1, role).getSingleResult();
+ } else {
+ return (SecurityMapping) getEntityManager().createQuery(
+ "select mapping from SecurityMapping mapping where mapping.role = ?1 and mapping.idForRole = ?2")
+ .setParameter(1, role).setParameter(2, idForRole).getSingleResult();
+ }
+ } catch (NoResultException e) {
+ SecurityMapping mapping = new SecurityMapping();
+ mapping.setRole(role);
+ mapping.setIdForRole(idForRole);
+ mapping.setUsers(new ArrayList<SecurityUser>());
+ mapping.setGroups(new ArrayList<SecurityGroup>());
+ getEntityManager().persist(mapping);
+ getEntityManager().flush();
+
+ return mapping;
+ }
+ }
+}
\ No newline at end of file
Added: feeds100P26/src/action/org/jboss/blog/session/security/external/DummyExternalSecurityService.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/security/external/DummyExternalSecurityService.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/security/external/DummyExternalSecurityService.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,98 @@
+package org.jboss.blog.session.security.external;
+
+import org.jboss.seam.annotations.*;
+import org.jboss.seam.ScopeType;
+import org.jboss.blog.model.security.SecurityUser;
+import org.jboss.blog.model.security.SecurityGroup;
+import org.jboss.blog.model.security.RestrictedSecurityGroup;
+import org.jboss.blog.model.security.RestrictedSecurityUser;
+import org.jboss.blog.session.security.InvalidLoginException;
+
+import javax.persistence.EntityManager;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("externalSecurityService")
+ at AutoCreate
+ at Scope(ScopeType.STATELESS)
+ at Install(precedence = 15)
+public class DummyExternalSecurityService extends AbstractExternalSecurityService {
+ @In
+ private EntityManager entityManager;
+
+ protected EntityManager getEntityManager() {
+ return entityManager;
+ }
+
+ public SecurityUser authenticate(String username, String password) throws InvalidLoginException {
+ SecurityUser user = new SecurityUser();
+ user.setExternalId(username);
+
+ return getUnrestrictedSecurityUser(user);
+ }
+
+ public List<? extends RestrictedSecurityGroup> getAllGroups() {
+ List<RestrictedSecurityGroup> groups = new ArrayList<RestrictedSecurityGroup>();
+ groups.add(new SecurityGroup("group1", "1"));
+ groups.add(new SecurityGroup("group2", "2"));
+ groups.add(new SecurityGroup("group3", "3"));
+
+ return groups;
+ }
+
+ public List<? extends RestrictedSecurityUser> getUsers(int start, int count) {
+ List<RestrictedSecurityUser> users = new ArrayList<RestrictedSecurityUser>();
+ users.add(new SecurityUser("1", "1"));
+ users.add(new SecurityUser("2", "2"));
+ users.add(new SecurityUser("2", "3"));
+
+ return users;
+ }
+
+ public List<? extends RestrictedSecurityUser> getUsers(String filter, int start, int count) {
+ List<RestrictedSecurityUser> users = new ArrayList<RestrictedSecurityUser>();
+ users.add(new SecurityUser("1", "1"));
+ users.add(new SecurityUser("2", "2"));
+ users.add(new SecurityUser("2", "3"));
+
+ return users;
+ }
+
+ public List<SecurityGroup> getGroupsOfUser(SecurityUser securityUser) {
+ List<SecurityGroup> groups = new ArrayList<SecurityGroup>();
+ groups.add(getUnrestrictedSecurityGroup(
+ new SecurityGroup("group" + securityUser.getExternalId(), securityUser.getExternalId())));
+
+ return groups;
+ }
+
+ public List<? extends RestrictedSecurityUser> getUsersInGroup(RestrictedSecurityGroup securityGroup) {
+ List<SecurityUser> users = new ArrayList<SecurityUser>();
+ users.add(new SecurityUser(securityGroup.getExternalId(), securityGroup.getExternalId()));
+
+ return users;
+ }
+
+ public String getEmail(RestrictedSecurityUser securityUserUser) {
+ return "a at a.pl";
+ }
+
+ public String getDisplayName(RestrictedSecurityUser securityUser) {
+ return securityUser.getExternalId();
+ }
+
+ public String getDisplayName(RestrictedSecurityGroup securityGroup) {
+ if (securityGroup.getRealGroup() == null) {
+ securityGroup.setRealGroup("group" + securityGroup.getExternalId());
+ }
+
+ return securityGroup.getRealGroup().toString();
+ }
+
+ public RestrictedSecurityGroup getAdminGroup() {
+ return new SecurityGroup("group1", "1");
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/security/external/ExternalSecurityService.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/security/external/ExternalSecurityService.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/security/external/ExternalSecurityService.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,37 @@
+package org.jboss.blog.session.security.external;
+
+import org.jboss.blog.model.security.*;
+import org.jboss.blog.session.security.InvalidLoginException;
+
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public interface ExternalSecurityService {
+ SecurityUser authenticate(String username, String password) throws InvalidLoginException;
+
+ SecurityGroup getUnrestrictedSecurityGroup(RestrictedSecurityGroup securityGroup);
+
+ SecurityUser getUnrestrictedSecurityUser(RestrictedSecurityUser securityUser);
+
+ List<? extends RestrictedSecurityGroup> getAllGroups();
+
+ List<? extends RestrictedSecurityUser> getUsers(int start, int count);
+
+ List<? extends RestrictedSecurityUser> getUsers(String filter, int start, int count);
+
+ List<SecurityGroup> getGroupsOfUser(SecurityUser securityUser);
+
+ List<? extends RestrictedSecurityUser> getUsersInGroup(RestrictedSecurityGroup securityGroup);
+
+ String getEmail(RestrictedSecurityUser securityUser);
+
+ String getDisplayName(RestrictedSecurityUser securityUser);
+
+ String getDisplayName(RestrictedSecurityGroup securityGroup);
+
+ RestrictedSecurityGroup getAdminGroup();
+
+ SecurityMapping getMapping(FeedsSecurityRole role, Integer idForRole);
+}
Added: feeds100P26/src/action/org/jboss/blog/session/security/filtering/FeedsSecurity.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/security/filtering/FeedsSecurity.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/security/filtering/FeedsSecurity.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,36 @@
+package org.jboss.blog.session.security.filtering;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.ScopeType;
+import org.jboss.blog.session.security.FeedsIdentity;
+import org.jboss.blog.model.feed.Feed;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("feedsSecurity")
+ at Scope(ScopeType.STATELESS)
+ at AutoCreate
+public class FeedsSecurity {
+ @In
+ private FeedsIdentity identity;
+
+ public List<Feed> filterViewableFeeds(List<Feed> feeds) {
+ ArrayList<Feed> ret = new ArrayList<Feed>();
+
+ for (Feed feed : feeds) {
+ boolean isFeedRestricted = feed.isFeedRestricted();
+ if (!isFeedRestricted || identity.hasPermission("feed", "view", feed)) {
+ ret.add(feed);
+ }
+ }
+
+ return ret;
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/security/filtering/GroupsSecurity.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/security/filtering/GroupsSecurity.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/security/filtering/GroupsSecurity.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,49 @@
+package org.jboss.blog.session.security.filtering;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.ScopeType;
+import org.jboss.blog.model.Group;
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.session.security.FeedsIdentity;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("groupsSecurity")
+ at Scope(ScopeType.STATELESS)
+ at AutoCreate
+public class GroupsSecurity {
+ @In
+ private FeedsIdentity identity;
+
+ public List<Group> filterForFeedMod(List<Group> groups) {
+ List<Group> allowedGroups = new ArrayList<Group>();
+
+ for (Group group : groups) {
+ if (identity.hasPermission("feed", "add", group)) {
+ allowedGroups.add(group);
+ }
+ }
+
+ return allowedGroups;
+ }
+
+ public List<Group> filterForFeedMod(Feed feed, List<Group> groups, boolean add) {
+ List<Group> allowedGroups = new ArrayList<Group>();
+
+ for (Group group : groups) {
+ if ((identity.hasPermission("feed", "add", feed, group)) ||
+ ((!add) && identity.hasPermission("feed", "edit", feed, group))) {
+ allowedGroups.add(group);
+ }
+ }
+
+ return allowedGroups;
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/security/filtering/HighlightsSecurity.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/security/filtering/HighlightsSecurity.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/security/filtering/HighlightsSecurity.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,46 @@
+package org.jboss.blog.session.security.filtering;
+
+import org.jboss.seam.annotations.*;
+import org.jboss.seam.ScopeType;
+import org.jboss.blog.model.feed.HighlightsFeed;
+import org.jboss.blog.session.security.FeedsIdentity;
+
+import javax.persistence.EntityManager;
+import java.util.List;
+import java.util.ArrayList;
+import java.io.Serializable;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("highlightsSecurity")
+ at Scope(ScopeType.CONVERSATION)
+ at AutoCreate
+public class HighlightsSecurity implements Serializable {
+ @In
+ private EntityManager entityManager;
+
+ @In
+ private FeedsIdentity identity;
+
+ private List<HighlightsFeed> feeds;
+
+ private void initFeeds() {
+ feeds = new ArrayList<HighlightsFeed>();
+
+ for (Object feedObj : entityManager.createQuery("select feed from HighlightsFeed feed").getResultList()) {
+ HighlightsFeed feed = (HighlightsFeed) feedObj;
+ if (identity.hasPermission("feed", "edit", feed, feed.getGroup())) {
+ feeds.add(feed);
+ }
+ }
+ }
+
+ public List<HighlightsFeed> getFeeds() {
+ if (feeds == null) {
+ initFeeds();
+ }
+
+ return feeds;
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/security/tools/FeedSecurityTools.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/security/tools/FeedSecurityTools.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/security/tools/FeedSecurityTools.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,23 @@
+package org.jboss.blog.session.security.tools;
+
+import org.jboss.blog.model.feed.RestrictedFeed;
+import org.jboss.seam.security.Identity;
+import org.jboss.seam.Component;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class FeedSecurityTools {
+ public static boolean canViewFeed(RestrictedFeed feed, boolean restricted) {
+ if (!feed.isFeedRestricted()) {
+ return true;
+ }
+
+ if (!restricted) {
+ return false;
+ }
+
+ Identity identity = (Identity) Component.getInstance(Identity.class);
+ return identity.hasPermission("feed", "view", feed);
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/tools/AdminBean.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/tools/AdminBean.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/tools/AdminBean.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,121 @@
+package org.jboss.blog.session.tools;
+
+import org.jboss.seam.annotations.*;
+import org.jboss.seam.annotations.security.Restrict;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.faces.FacesMessages;
+import org.jboss.seam.log.Log;
+import org.jboss.blog.model.Group;
+import org.jboss.blog.model.Post;
+import org.jboss.blog.model.XmlType;
+import org.jboss.blog.model.Template;
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.tools.StringTools;
+import org.jboss.blog.service.GroupsService;
+import org.jboss.blog.session.cache.CacheManager;
+import org.jboss.blog.session.xml.velocity.TemplateServiceBean;
+
+import javax.persistence.EntityManager;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Scope(ScopeType.STATELESS)
+ at Name("adminBean")
+ at AutoCreate
+public class AdminBean {
+ @In
+ private GroupsService groupsService;
+
+ @In
+ private EntityManager entityManager;
+
+ @In
+ private CacheManager cacheManager;
+
+ @In
+ private FacesMessages facesMessages;
+
+ @In
+ private TemplateServiceBean templateService;
+
+ @Logger
+ private Log log;
+
+ private void updateFeedTemplates(Template atomTemplate, Template rss2Template, Template rss1Template, Feed feed) {
+ if (feed.getTemplates().get(XmlType.ATOM) == null) { feed.getTemplates().put(XmlType.ATOM, atomTemplate); }
+ if (feed.getTemplates().get(XmlType.RSS2) == null) { feed.getTemplates().put(XmlType.RSS2, rss2Template); }
+ if (feed.getTemplates().get(XmlType.RSS1) == null) { feed.getTemplates().put(XmlType.RSS1, rss1Template); }
+ }
+
+ public void updateMissingTemplates() {
+ Template atomTemplate = templateService.templatesOfType(XmlType.ATOM).get(0);
+ Template rss2Template = templateService.templatesOfType(XmlType.RSS2).get(0);
+ Template rss1Template = templateService.templatesOfType(XmlType.RSS1).get(0);
+
+ for (Group group : groupsService.getAllGroups()) {
+ for (Feed feed : groupsService.unacceptedFeeds(group)) {
+ updateFeedTemplates(atomTemplate, rss2Template, rss1Template, feed);
+ }
+
+ for (Feed feed : groupsService.allAcceptedFeeds(group)) {
+ updateFeedTemplates(atomTemplate, rss2Template, rss1Template, feed);
+ }
+ }
+ }
+
+ @Restrict("#{identity.hasPermission('admin', null)}")
+ public void fixHtml() {
+ for (Group group : groupsService.getAllGroups()) {
+ for (Feed feed : groupsService.acceptedFeeds(group)) {
+ for (Post post : feed.getPosts()) {
+ post.setContent(StringTools.fixHtml(post.getContent()));
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings({"unchecked"})
+ @Restrict("#{identity.hasPermission('admin', null)}")
+ public void removeDuplicates() {
+ List<Object[]> results = (List<Object[]>) entityManager
+ .createQuery("select title, published, count(*) from Post p group by p.title, p.published")
+ .getResultList();
+
+ int removedDuplicates = 0;
+
+ for (Object[] result : results) {
+ if (((Number) result[2]).intValue() > 1) {
+ log.info("Duplicate post with title: " + result[0] + ", published: " + result[1] +
+ ", count: " + result[2]);
+
+ removedDuplicates += ((Number) result[2]).intValue();
+
+ String titleAsId = StringTools.convertTitleToLink(result[0].toString());
+
+ // Checking that a "first" post exists
+ List firstPostResult = entityManager
+ .createQuery("select p from Post p where p.titleAsId = :titleAsId")
+ .setParameter("titleAsId", titleAsId)
+ .getResultList();
+
+ if (firstPostResult.size() != 1) {
+ log.info("No first post with titleAsId = " + titleAsId + "!");
+ } else {
+ entityManager
+ .createQuery("delete from Post p where p.titleAsId like :titleAsIdLike " +
+ "and p.titleAsId != :titleAsId and p.published = :published")
+ .setParameter("titleAsIdLike", titleAsId + "%")
+ .setParameter("titleAsId", titleAsId)
+ .setParameter("published", result[1])
+ .executeUpdate();
+ }
+ }
+ }
+
+ cacheManager.evictAll();
+
+ facesMessages.add("Removed " + removedDuplicates + " duplicate posts.");
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/tools/CaptchaToolsBean.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/tools/CaptchaToolsBean.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/tools/CaptchaToolsBean.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,18 @@
+package org.jboss.blog.session.tools;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.ScopeType;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("captchaTools")
+ at Scope(ScopeType.STATELESS)
+ at AutoCreate
+public class CaptchaToolsBean {
+ public long getId() {
+ return System.currentTimeMillis();
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/tools/PostToToolsBean.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/tools/PostToToolsBean.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/tools/PostToToolsBean.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,64 @@
+package org.jboss.blog.session.tools;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.ScopeType;
+import org.jboss.blog.model.Post;
+
+import java.net.URLEncoder;
+import java.io.UnsupportedEncodingException;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("postToTools")
+ at Scope(ScopeType.APPLICATION)
+ at AutoCreate
+public class PostToToolsBean {
+ public String encodeTitleForDelicious(Post post) {
+ try {
+ return URLEncoder.encode(post.getTitle(), "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ return post.getTitle();
+ }
+ }
+
+ public String encodeLink(Post post) {
+ String link = post.getLink();
+ int hashPos;
+ if ((hashPos = link.indexOf('#')) != -1) {
+ link = link.substring(0, hashPos);
+ }
+
+ try {
+ return URLEncoder.encode(link, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ return link;
+ }
+ }
+
+ public String encodeTitleForDigg(Post post) {
+ try {
+ String title = post.getTitle();
+ if (title.length() > 75) {
+ title = title.substring(0, 75);
+ }
+ return URLEncoder.encode(title, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ return "";
+ }
+ }
+
+ public String encodeBodyForDigg(Post post) {
+ try {
+ String content = post.getContent();
+ if (content.length() > 350) {
+ content = content.substring(0, 350);
+ }
+ return URLEncoder.encode(content, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ return "";
+ }
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/tools/StringToolsBean.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/tools/StringToolsBean.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/tools/StringToolsBean.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,33 @@
+package org.jboss.blog.session.tools;
+
+import org.jboss.blog.tools.StringTools;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("stringTools")
+ at Scope(ScopeType.APPLICATION)
+ at AutoCreate
+public class StringToolsBean {
+ private volatile int summaryLength;
+
+ public StringToolsBean() {
+ summaryLength = 500;
+ }
+
+ public int getSummaryLength() {
+ return summaryLength;
+ }
+
+ public void setSummaryLength(int summaryLength) {
+ this.summaryLength = summaryLength;
+ }
+
+ public String createSummary(String s) {
+ return StringTools.createSummary(s, summaryLength);
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/update/UpdateException.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/update/UpdateException.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/update/UpdateException.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,21 @@
+package org.jboss.blog.session.update;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class UpdateException extends Exception {
+ public UpdateException() {
+ }
+
+ public UpdateException(String message) {
+ super(message);
+ }
+
+ public UpdateException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public UpdateException(Throwable cause) {
+ super(cause);
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/update/UpdateHandler.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/update/UpdateHandler.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/update/UpdateHandler.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,82 @@
+package org.jboss.blog.session.update;
+
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.feed.RestrictedFeed;
+import org.jboss.blog.model.Group;
+import org.jboss.blog.service.GroupsService;
+import org.jboss.blog.service.FeedsService;
+import org.jboss.blog.service.FeedNotFoundException;
+import org.jboss.blog.session.feed.type.FeedTypes;
+import org.jboss.blog.session.security.FeedsIdentity;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.ScopeType;
+
+import javax.ejb.Remove;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("updateHandler")
+ at Scope(ScopeType.STATELESS)
+ at AutoCreate
+public class UpdateHandler {
+ @In
+ private GroupsService groupsService;
+
+ @In
+ private FeedsService feedsService;
+
+ @In
+ private FeedTypes feedTypes;
+
+ @In
+ private UpdateManager updateManager;
+
+ @In(create = true)
+ private FeedsIdentity identity;
+
+ public List<String> getFeedsToUpdate() {
+ List<String> ret = new ArrayList<String>();
+
+ for (Group group : groupsService.getAllGroups()) {
+ for (Feed feed : groupsService.acceptedFeeds(group)) {
+ ret.add(feed.getName());
+ }
+
+ for (Feed feed : groupsService.restrictedFeeds(group)) {
+ ret.add(feed.getName());
+ }
+ }
+
+ return ret;
+ }
+
+ public void update(String feedName) {
+ try {
+ update(feedsService.getFeed(feedName));
+ } catch (FeedNotFoundException e) {
+ //noinspection ThrowableInstanceNeverThrown
+ updateManager.addFeedUpdateException(feedName, new UpdateException(e));
+ }
+ }
+
+ public void update(RestrictedFeed feed) {
+ identity.loginAsAdmin();
+ try {
+ feedTypes.getFeedDao(feed).update();
+ } catch (UpdateException e) {
+ updateManager.addFeedUpdateException(feed.getName(), e);
+ } catch (Exception e) {
+ //noinspection ThrowableInstanceNeverThrown
+ updateManager.addFeedUpdateException(feed.getName(), new UpdateException(e));
+ }
+ }
+
+ @Remove
+ public void remove() { }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/update/UpdateHandlerAsync.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/update/UpdateHandlerAsync.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/update/UpdateHandlerAsync.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,17 @@
+package org.jboss.blog.session.update;
+
+import org.jboss.blog.model.feed.RestrictedFeed;
+import org.jboss.seam.annotations.async.Asynchronous;
+
+import javax.ejb.Local;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Local
+public interface UpdateHandlerAsync {
+ @Asynchronous
+ public void update(RestrictedFeed feed);
+
+ public void remove();
+}
Added: feeds100P26/src/action/org/jboss/blog/session/update/UpdateHandlerAsyncImpl.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/update/UpdateHandlerAsyncImpl.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/update/UpdateHandlerAsyncImpl.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,27 @@
+package org.jboss.blog.session.update;
+
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.blog.model.feed.RestrictedFeed;
+
+import javax.ejb.Stateless;
+import javax.ejb.Remove;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Stateless
+ at Name("updateHandlerAsync")
+ at AutoCreate
+public class UpdateHandlerAsyncImpl implements UpdateHandlerAsync {
+ @In
+ private UpdateHandler updateHandler;
+
+ public void update(RestrictedFeed feed) {
+ updateHandler.update(feed);
+ }
+
+ @Remove
+ public void remove() { }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/update/UpdateManager.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/update/UpdateManager.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/update/UpdateManager.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,168 @@
+package org.jboss.blog.session.update;
+
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.faces.FacesMessages;
+import org.jboss.seam.annotations.*;
+import org.jboss.seam.annotations.Observer;
+import org.jboss.seam.annotations.security.Restrict;
+import org.jboss.blog.session.configuration.ConfigurationManager;
+import org.jboss.blog.tools.GeneralTools;
+
+import javax.faces.application.FacesMessage;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.*;
+import java.text.DateFormat;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("updateManager")
+ at Scope(ScopeType.APPLICATION)
+public class UpdateManager {
+ @In
+ private ConfigurationManager configurationManager;
+
+ @In
+ private FacesMessages facesMessages;
+
+ private long lastUpdateStart;
+ private long lastUpdateEnd;
+
+ private AtomicBoolean updateInProgress;
+
+ private List<Exception> globalExceptions;
+ private Map<String, List<UpdateException>> feedUpdateExceptions;
+
+ private ScheduledExecutorService executor;
+
+ @Observer("org.jboss.blog.postBlogInit")
+ @Transactional
+ public void register() {
+ globalExceptions = new ArrayList<Exception>();
+ feedUpdateExceptions = new LinkedHashMap<String, List<UpdateException>>();
+
+ createAndStartExcutor();
+ }
+
+ public void restartUpdateThread() {
+ executor.shutdown();
+ createAndStartExcutor();
+ }
+
+ private void createAndStartExcutor() {
+ executor = Executors.newScheduledThreadPool(1);
+ executor.scheduleAtFixedRate(new UpdateThread(), 10, getUpdateInterval(), TimeUnit.SECONDS);
+
+ updateInProgress = new AtomicBoolean(false);
+ }
+
+ public void addFeedUpdateException(String feedName, UpdateException exception) {
+ List<UpdateException> exceptions = feedUpdateExceptions.get(feedName);
+ if (exceptions == null) {
+ exceptions = new ArrayList<UpdateException>();
+ feedUpdateExceptions.put(feedName, exceptions);
+ }
+
+ if (exceptions.size() < 3) {
+ exceptions.add(exception);
+ }
+ }
+
+ public void addGlobalException(Exception exception) {
+ if (globalExceptions.size() < 3) {
+ globalExceptions.add(exception);
+ }
+ }
+
+ public List<UpdateException> getFeedUpdateExceptionsForFeed(String feedName) {
+ return feedUpdateExceptions.get(feedName);
+ }
+
+ public List<String> getFeedUpdateExceptionNames() {
+ return new ArrayList<String>(feedUpdateExceptions.keySet());
+ }
+
+ public void clearFeedsExceptions() {
+ feedUpdateExceptions.clear();
+ }
+
+ public List<Exception> getGlobalExceptions() {
+ return globalExceptions;
+ }
+
+ public void clearGlobalExceptions() {
+ globalExceptions.clear();
+ }
+
+ public long getLastUpdateEnd() {
+ return lastUpdateEnd;
+ }
+
+ public void setLastUpdateEnd(long lastUpdateEnd) {
+ this.lastUpdateEnd = lastUpdateEnd;
+ }
+
+ public String getLastUpdateEndDate() {
+ return DateFormat.getDateTimeInstance().format(getLastUpdateEnd());
+ }
+
+ public long getLastUpdateStart() {
+ return lastUpdateStart;
+ }
+
+ public void setLastUpdateStart(long lastUpdateStart) {
+ this.lastUpdateStart = lastUpdateStart;
+ }
+
+ public String getLastUpdateStartDate() {
+ return DateFormat.getDateTimeInstance().format(getLastUpdateStart());
+ }
+
+ public AtomicBoolean getUpdateInProgress() {
+ return updateInProgress;
+ }
+
+ public String getNow() {
+ return DateFormat.getDateTimeInstance().format(System.currentTimeMillis());
+ }
+
+ public int getUpdateInterval() {
+ return configurationManager.getConfiguration().getUpdateInterval();
+ }
+
+ @Restrict("#{identity.hasPermission('admin', null)}")
+ public void setUpdateInterval(int updateInterval) {
+ configurationManager.getConfiguration().setUpdateInterval(updateInterval);
+ }
+
+ public int getConnectionTimeout() {
+ return configurationManager.getConfiguration().getConnectionTimeout();
+ }
+
+ @Restrict("#{identity.hasPermission('admin', null)}")
+ public void setConnectionTimeout(int connectionTimeout) {
+ configurationManager.getConfiguration().setConnectionTimeout(connectionTimeout);
+ }
+
+ public int getReadTimeout() {
+ return configurationManager.getConfiguration().getReadTimeout();
+ }
+
+ @Restrict("#{identity.hasPermission('admin', null)}")
+ public void setReadTimeout(int readTimeout) {
+ configurationManager.getConfiguration().setReadTimeout(readTimeout);
+ }
+
+ public String getExceptionStackTrace(Exception e) {
+ return GeneralTools.getExceptionStackTrace(e);
+ }
+
+ @Restrict("#{identity.hasPermission('admin', null)}")
+ public void save() {
+ restartUpdateThread();
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, "blog.configuration.saved");
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/update/UpdateThread.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/update/UpdateThread.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/update/UpdateThread.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,111 @@
+package org.jboss.blog.session.update;
+
+import org.jboss.seam.contexts.Contexts;
+import org.jboss.seam.contexts.Lifecycle;
+import org.jboss.seam.Component;
+import org.jboss.seam.log.Logging;
+
+import javax.transaction.UserTransaction;
+import javax.transaction.Status;
+import java.text.DateFormat;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class UpdateThread implements Runnable {
+ public void run() {
+ List<String> feedsToUpdate = executeInTransaction(new RunnableWithReturn<List<String>>() {
+ public List<String> run() {
+ UpdateManager updateManager = (UpdateManager) Component.getInstance("updateManager");
+
+ if (!updateManager.getUpdateInProgress().getAndSet(true)) {
+ updateManager.setLastUpdateStart(System.currentTimeMillis());
+
+ return ((UpdateHandler) Component.getInstance("updateHandler")).getFeedsToUpdate();
+ } else {
+ //noinspection ThrowableInstanceNeverThrown
+ updateManager.addGlobalException(new Exception("New update started before the last one finished, " +
+ "at " + DateFormat.getDateTimeInstance().format(new Date()) + "!"));
+
+ updateManager.setLastUpdateEnd(System.currentTimeMillis());
+ updateManager.getUpdateInProgress().set(false);
+ return null;
+ }
+ }
+ });
+
+ if (feedsToUpdate != null) {
+ for (final String feedName : feedsToUpdate) {
+ executeInTransaction(new RunnableWithReturn<Object>() {
+ public Object run() {
+ ((UpdateHandler) Component.getInstance("updateHandler")).update(feedName);
+ return null;
+ }
+ });
+ }
+
+ executeInTransaction(new RunnableWithReturn<Object>() {
+ public List<Object> run() {
+ UpdateManager updateManager = (UpdateManager) Component.getInstance("updateManager");
+
+ updateManager.setLastUpdateEnd(System.currentTimeMillis());
+ updateManager.getUpdateInProgress().set(false);
+
+ return null;
+ }
+ });
+ }
+ }
+
+ private <T> T executeInTransaction(RunnableWithReturn<T> runnable) {
+ try {
+ boolean createContexts = !Contexts.isEventContextActive() && !Contexts.isApplicationContextActive();
+ if (createContexts) {
+ Lifecycle.beginCall();
+ }
+
+ try {
+ UserTransaction tx = null;
+ boolean txStarted = false;
+ try {
+ tx = (UserTransaction) Component.getInstance("org.jboss.seam.transaction.transaction");
+ if (tx.getStatus() != Status.STATUS_ACTIVE) {
+ txStarted = true;
+ tx.begin();
+ }
+
+ T ret = runnable.run();
+
+ if (txStarted) {
+ tx.commit();
+ }
+
+ return ret;
+ } catch (Throwable e) {
+ try {
+ if (txStarted) {
+ tx.rollback();
+ }
+ } catch (Throwable e1) {
+ Logging.getLog(UpdateManager.class).error("Exception when rolling back the transaction", e1);
+ }
+
+ return null;
+ }
+ } finally {
+ if (createContexts) {
+ Lifecycle.endCall();
+ }
+ }
+ } catch (Throwable t) {
+ Logging.getLog(UpdateManager.class).error("Exception when updating!", t);
+ return null;
+ }
+ }
+
+ private static interface RunnableWithReturn<T> {
+ T run();
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/validator/UniqueFeedNameValidator.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/validator/UniqueFeedNameValidator.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/validator/UniqueFeedNameValidator.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,62 @@
+package org.jboss.blog.session.validator;
+
+import org.jboss.blog.tools.StringTools;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.faces.Validator;
+import org.jboss.seam.international.Messages;
+
+import javax.faces.application.FacesMessage;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.validator.ValidatorException;
+import javax.persistence.EntityManager;
+import javax.persistence.Query;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Validator
+ at Name("uniqueFeedNameValidator")
+public class UniqueFeedNameValidator implements javax.faces.validator.Validator {
+ @In
+ private EntityManager entityManager;
+
+ private String entityId;
+
+ public String getEntityId() {
+ return entityId;
+ }
+
+ public void setEntityId(String entityId) {
+ this.entityId = entityId;
+ }
+
+ public void validate(FacesContext context, UIComponent cmp, Object value)
+ throws ValidatorException {
+ String name = StringTools.safeToString(value);
+
+ Integer id;
+
+ if (StringTools.isEmpty(entityId)) {
+ id = null;
+ } else {
+ id = Integer.parseInt(entityId);
+ }
+
+ Query query;
+
+ if (id == null) {
+ query = entityManager.createQuery("select feed.id from Feed feed where feed.name = ?1")
+ .setParameter(1, name);
+ } else {
+ query = entityManager.createQuery(
+ "select feed.id from Feed feed where feed.name = ?1 and not (feed.id = ?2)")
+ .setParameter(1, name).setParameter(2, id);
+ }
+
+ if (query.getResultList().size() != 0) {
+ throw new ValidatorException(new FacesMessage(Messages.instance().get("blog.feed.new.existingname")));
+ }
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/validator/UniqueGroupNameValidator.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/validator/UniqueGroupNameValidator.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/validator/UniqueGroupNameValidator.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,62 @@
+package org.jboss.blog.session.validator;
+
+import org.jboss.blog.tools.StringTools;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.faces.Validator;
+import org.jboss.seam.international.Messages;
+
+import javax.faces.application.FacesMessage;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.validator.ValidatorException;
+import javax.persistence.EntityManager;
+import javax.persistence.Query;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Validator
+ at Name("uniqueGroupNameValidator")
+public class UniqueGroupNameValidator implements javax.faces.validator.Validator {
+ @In
+ private EntityManager entityManager;
+
+ private String entityId;
+
+ public String getEntityId() {
+ return entityId;
+ }
+
+ public void setEntityId(String entityId) {
+ this.entityId = entityId;
+ }
+
+ public void validate(FacesContext context, UIComponent cmp, Object value)
+ throws ValidatorException {
+ String name = StringTools.safeToString(value);
+
+ Integer id;
+
+ if (StringTools.isEmpty(entityId)) {
+ id = null;
+ } else {
+ id = Integer.parseInt(entityId);
+ }
+
+ Query query;
+
+ if (id == null) {
+ query = entityManager.createQuery("select g.id from Group g where g.name = ?1")
+ .setParameter(1, name);
+ } else {
+ query = entityManager.createQuery(
+ "select g.id from Group g where g.name = ?1 and not (g.id = ?2)")
+ .setParameter(1, name).setParameter(2, id);
+ }
+
+ if (query.getResultList().size() != 0) {
+ throw new ValidatorException(new FacesMessage(Messages.instance().get("blog.group.existingname")));
+ }
+ }
+}
\ No newline at end of file
Added: feeds100P26/src/action/org/jboss/blog/session/validator/UniqueTemplateNameValidator.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/validator/UniqueTemplateNameValidator.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/validator/UniqueTemplateNameValidator.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,62 @@
+package org.jboss.blog.session.validator;
+
+import org.jboss.blog.tools.StringTools;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.faces.Validator;
+import org.jboss.seam.international.Messages;
+
+import javax.faces.application.FacesMessage;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.validator.ValidatorException;
+import javax.persistence.EntityManager;
+import javax.persistence.Query;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Validator
+ at Name("uniqueTemplateNameValidator")
+public class UniqueTemplateNameValidator implements javax.faces.validator.Validator {
+ @In
+ private EntityManager entityManager;
+
+ private String entityId;
+
+ public String getEntityId() {
+ return entityId;
+ }
+
+ public void setEntityId(String entityId) {
+ this.entityId = entityId;
+ }
+
+ public void validate(FacesContext context, UIComponent cmp, Object value)
+ throws ValidatorException {
+ String name = StringTools.safeToString(value);
+
+ Integer id;
+
+ if (StringTools.isEmpty(entityId)) {
+ id = null;
+ } else {
+ id = Integer.parseInt(entityId);
+ }
+
+ Query query;
+
+ if (id == null) {
+ query = entityManager.createQuery("select t.id from Template t where t.name = ?1")
+ .setParameter(1, name);
+ } else {
+ query = entityManager.createQuery(
+ "select t.id from Template t where t.name = ?1 and not (t.id = ?2)")
+ .setParameter(1, name).setParameter(2, id);
+ }
+
+ if (query.getResultList().size() != 0) {
+ throw new ValidatorException(new FacesMessage(Messages.instance().get("blog.template.new.existingname")));
+ }
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/view/FeedViewBean.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/view/FeedViewBean.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/view/FeedViewBean.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,67 @@
+package org.jboss.blog.session.view;
+
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.RestrictedPost;
+import org.jboss.blog.service.FeedsService;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+
+import java.util.List;
+import java.io.Serializable;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("feedView")
+ at Scope(ScopeType.CONVERSATION)
+public class FeedViewBean implements Serializable {
+ @In
+ private FeedsService feedsService;
+
+ private Feed feed;
+ private int from;
+
+ private List<? extends RestrictedPost> posts;
+
+ public Feed getFeed() {
+ return feed;
+ }
+
+ public void setFeed(Feed feed) {
+ this.feed = feed;
+ }
+
+ public int getFrom() {
+ return from;
+ }
+
+ public void setFrom(int from) {
+ this.from = from;
+ }
+
+ public List<? extends RestrictedPost> getPosts() {
+ if (posts == null) {
+ posts = feedsService.getPosts(feed, from, from+feed.getMaxPostsOnPage()+1);
+ }
+
+ return posts;
+ }
+
+ public boolean getShowPrevious() {
+ return from != 0;
+ }
+
+ public boolean getShowNext() {
+ return getPosts().size() == feed.getMaxPostsOnPage()+1;
+ }
+
+ public int getPreviousFrom() {
+ return Math.max(0, from - feed.getMaxPostsOnPage());
+ }
+
+ public int getNextFrom() {
+ return from + feed.getMaxPostsOnPage();
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/view/LinkServiceImpl.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/view/LinkServiceImpl.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/view/LinkServiceImpl.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,61 @@
+package org.jboss.blog.session.view;
+
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.Post;
+import org.jboss.blog.model.XmlType;
+import org.jboss.blog.service.LinkService;
+import org.jboss.blog.session.security.SecurityUserKeys;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.ScopeType;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at AutoCreate
+ at Scope(ScopeType.STATELESS)
+ at Name("linkService")
+public class LinkServiceImpl implements LinkService {
+ @In
+ private SecurityUserKeys securityUserKeys;
+
+ private String serverAddress;
+ private String contextName;
+
+ public String getServerAddress() {
+ return serverAddress;
+ }
+
+ public void setServerAddress(String serverAddress) {
+ this.serverAddress = serverAddress;
+ }
+
+ public String getContextName() {
+ return contextName;
+ }
+
+ public void setContextName(String contextName) {
+ this.contextName = contextName;
+ }
+
+ public String generateFeedLink(Feed feed, XmlType type) {
+ String base = serverAddress + "/" + contextName + "/xml/" + feed.getName()
+ + "?type=" + type.toString().toLowerCase();
+
+ if (feed.isFeedRestricted()) {
+ return base + "&key=" + securityUserKeys.getKeyOfCurrentUser();
+ } else {
+ return base;
+ }
+ }
+
+ public String generateFeedPageLink(Feed feed) {
+ return serverAddress + "/" + contextName + "/view/" + feed.getName();
+ }
+
+ public String generatePostLink(Post post) {
+ return serverAddress + "/" + contextName + "/post/" + post.getTitleAsId();
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/view/PostViewBean.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/view/PostViewBean.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/view/PostViewBean.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,34 @@
+package org.jboss.blog.session.view;
+
+import org.jboss.blog.model.Post;
+import org.jboss.blog.session.merge.PostManager;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.security.Restrict;
+
+import java.io.Serializable;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("postView")
+public class PostViewBean implements Serializable {
+ @In
+ private PostManager postManager;
+
+ private Post post;
+
+ public Post getPost() {
+ return post;
+ }
+
+ public void setPost(Post post) {
+ this.post = post;
+ }
+
+ // TODO: the delete method shouldn't be here
+ @Restrict("#{identity.hasPermission('post', 'delete', postView.post, postView.post.feed, postView.post.feed.group)}")
+ public void delete() {
+ postManager.deletePost(post);
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/xml/XmlService.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/xml/XmlService.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/xml/XmlService.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,11 @@
+package org.jboss.blog.session.xml;
+
+import org.jboss.blog.session.xml.content.ContentResponse;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public interface XmlService {
+ void writeXml(String feedType, String feedName, String feedKey, ContentResponse response)
+ throws Exception;
+}
Added: feeds100P26/src/action/org/jboss/blog/session/xml/content/ContentResponse.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/xml/content/ContentResponse.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/xml/content/ContentResponse.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,19 @@
+package org.jboss.blog.session.xml.content;
+
+import java.io.Writer;
+import java.io.IOException;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public interface ContentResponse {
+ public String getContentType();
+
+ public void setContentType(String contentType);
+
+ public String getCharacterEncoding();
+
+ public void setCharacterEncoding(String characterEncoding);
+
+ public Writer getWriter() throws IOException;
+}
Added: feeds100P26/src/action/org/jboss/blog/session/xml/content/InMemoryContentResponse.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/xml/content/InMemoryContentResponse.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/xml/content/InMemoryContentResponse.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,37 @@
+package org.jboss.blog.session.xml.content;
+
+import java.io.Writer;
+import java.io.CharArrayWriter;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class InMemoryContentResponse implements ContentResponse {
+ private String contentType;
+ private String characterEncoding;
+ private CharArrayWriter writer;
+
+ public InMemoryContentResponse() {
+ writer = new CharArrayWriter();
+ }
+
+ public String getContentType() {
+ return contentType;
+ }
+
+ public void setContentType(String contentType) {
+ this.contentType = contentType;
+ }
+
+ public String getCharacterEncoding() {
+ return characterEncoding;
+ }
+
+ public void setCharacterEncoding(String characterEncoding) {
+ this.characterEncoding = characterEncoding;
+ }
+
+ public Writer getWriter() {
+ return writer;
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/xml/content/ServletResponseContentResponse.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/xml/content/ServletResponseContentResponse.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/xml/content/ServletResponseContentResponse.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,37 @@
+package org.jboss.blog.session.xml.content;
+
+import javax.servlet.ServletResponse;
+import java.io.Writer;
+import java.io.PrintWriter;
+import java.io.IOException;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class ServletResponseContentResponse implements ContentResponse {
+ private ServletResponse servletResponse;
+
+ public ServletResponseContentResponse(ServletResponse servletResponse) {
+ this.servletResponse = servletResponse;
+ }
+
+ public String getCharacterEncoding() {
+ return servletResponse.getCharacterEncoding();
+ }
+
+ public String getContentType() {
+ return servletResponse.getContentType();
+ }
+
+ public Writer getWriter() throws IOException {
+ return servletResponse.getWriter();
+ }
+
+ public void setCharacterEncoding(String s) {
+ servletResponse.setCharacterEncoding(s);
+ }
+
+ public void setContentType(String s) {
+ servletResponse.setContentType(s);
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/xml/velocity/DatabaseResourceLoader.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/xml/velocity/DatabaseResourceLoader.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/xml/velocity/DatabaseResourceLoader.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,50 @@
+package org.jboss.blog.session.xml.velocity;
+
+import org.apache.commons.collections.ExtendedProperties;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.runtime.resource.Resource;
+import org.apache.velocity.runtime.resource.loader.ResourceLoader;
+import org.jboss.blog.model.Template;
+import org.jboss.seam.Component;
+
+import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class DatabaseResourceLoader extends ResourceLoader {
+ public void init(ExtendedProperties extendedProperties) {
+ }
+
+ private Template getTemplate(String name) {
+ return (Template) ((EntityManager) Component.getInstance("entityManager")).createQuery(
+ "select t from Template t where t.name = ?1").setParameter(1, name).getSingleResult();
+ }
+
+ public InputStream getResourceStream(String name) throws ResourceNotFoundException {
+ try {
+ return new ByteArrayInputStream(getTemplate(name).getText().getBytes());
+ } catch (NoResultException e) {
+ return null;
+ }
+ }
+
+ public boolean isSourceModified(Resource resource) {
+ try {
+ return resource.getLastModified() != getLastModified(resource);
+ } catch (NoResultException e) {
+ return false;
+ }
+ }
+
+ public long getLastModified(Resource resource) {
+ try {
+ return getTemplate(resource.getName()).getLastModified().getTime();
+ } catch (NoResultException e) {
+ return 0;
+ }
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/xml/velocity/InvalidTemplateTypeException.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/xml/velocity/InvalidTemplateTypeException.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/xml/velocity/InvalidTemplateTypeException.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,21 @@
+package org.jboss.blog.session.xml.velocity;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class InvalidTemplateTypeException extends Exception {
+ public InvalidTemplateTypeException() {
+ }
+
+ public InvalidTemplateTypeException(String message) {
+ super(message);
+ }
+
+ public InvalidTemplateTypeException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public InvalidTemplateTypeException(Throwable cause) {
+ super(cause);
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/xml/velocity/TemplateBootstrap.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/xml/velocity/TemplateBootstrap.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/xml/velocity/TemplateBootstrap.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,82 @@
+package org.jboss.blog.session.xml.velocity;
+
+import org.jboss.seam.annotations.*;
+import org.jboss.seam.ScopeType;
+import org.jboss.blog.model.Template;
+import org.jboss.blog.model.XmlType;
+import org.jboss.blog.tools.GeneralTools;
+
+import javax.persistence.EntityManager;
+import java.util.Date;
+import java.io.IOException;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("templateBootstrap")
+ at Scope(ScopeType.STATELESS)
+public class TemplateBootstrap {
+ @In
+ private EntityManager entityManager;
+
+ private long getTemplateCount(XmlType type) {
+ return (Long) entityManager
+ .createQuery("select count(t) from Template t where t.type = :type")
+ .setParameter("type", type)
+ .getSingleResult();
+ }
+
+ @Observer("org.jboss.blog.postBlogInit")
+ @Transactional
+ public void initAtomTemplate() throws IOException {
+ if (getTemplateCount(XmlType.ATOM) == 0) {
+ String templateText = GeneralTools.readInputStream(
+ this.getClass().getResourceAsStream("/templates/atom_standard.vm"));
+
+ Template atomTemplate = new Template();
+ atomTemplate.setType(XmlType.ATOM);
+ atomTemplate.setLastModified(new Date());
+ atomTemplate.setName("0_atom_standard");
+ atomTemplate.setText(templateText);
+
+ entityManager.persist(atomTemplate);
+ entityManager.flush();
+ }
+ }
+
+ @Observer("org.jboss.blog.postBlogInit")
+ @Transactional
+ public void initRss2Template() throws IOException {
+ if (getTemplateCount(XmlType.RSS2) == 0) {
+ String templateText = GeneralTools.readInputStream(
+ this.getClass().getResourceAsStream("/templates/rss2_standard.vm"));
+
+ Template rss2Template = new Template();
+ rss2Template.setType(XmlType.RSS2);
+ rss2Template.setLastModified(new Date());
+ rss2Template.setName("0_rss2_standard");
+ rss2Template.setText(templateText);
+
+ entityManager.persist(rss2Template);
+ entityManager.flush();
+ }
+ }
+
+ @Observer("org.jboss.blog.postBlogInit")
+ @Transactional
+ public void initRss1Template() throws IOException {
+ if (getTemplateCount(XmlType.RSS1) == 0) {
+ String templateText = GeneralTools.readInputStream(
+ this.getClass().getResourceAsStream("/templates/rss1_standard.vm"));
+
+ Template rss1Template = new Template();
+ rss1Template.setType(XmlType.RSS1);
+ rss1Template.setLastModified(new Date());
+ rss1Template.setName("0_rss1_standard");
+ rss1Template.setText(templateText);
+
+ entityManager.persist(rss1Template);
+ entityManager.flush();
+ }
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/xml/velocity/TemplateModBean.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/xml/velocity/TemplateModBean.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/xml/velocity/TemplateModBean.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,71 @@
+package org.jboss.blog.session.xml.velocity;
+
+import org.jboss.blog.model.Template;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.security.Restrict;
+import org.jboss.seam.faces.FacesMessages;
+import org.jboss.seam.core.Events;
+
+import javax.persistence.EntityManager;
+import javax.faces.application.FacesMessage;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("templateMod")
+public class TemplateModBean {
+ @In
+ private EntityManager entityManager;
+
+ @In
+ private FacesMessages facesMessages;
+
+ @In
+ private Events events;
+
+ private Template template;
+
+ public Template getTemplate() {
+ if (template == null) {
+ template = new Template();
+ }
+
+ return template;
+ }
+
+ public void setTemplate(Template template) {
+ this.template = template;
+ }
+
+ @Restrict("#{identity.hasPermission('template', 'add')}")
+ public void saveNew() {
+ entityManager.persist(template);
+ entityManager.flush();
+
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, "blog.template.added", template.getName(),
+ template.getType());
+
+ events.raiseEvent("org.jboss.blog.template.added", template);
+ }
+
+ @Restrict("#{identity.hasPermission('template', 'edit', templateMod.template)}")
+ public void saveExisting() {
+ entityManager.flush();
+
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, "blog.template.updated", template.getName(),
+ template.getType());
+
+ events.raiseEvent("org.jboss.blog.template.updated", template);
+ }
+
+ @Restrict("#{identity.hasPermission('template', 'delete', templateMod.template)}")
+ public void delete() {
+ entityManager.remove(template);
+
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, "blog.template.deleted", template.getName(),
+ template.getType());
+
+ events.raiseEvent("org.jboss.blog.template.deleted", template);
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/xml/velocity/TemplateServiceBean.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/xml/velocity/TemplateServiceBean.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/xml/velocity/TemplateServiceBean.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,34 @@
+package org.jboss.blog.session.xml.velocity;
+
+import org.jboss.blog.model.Template;
+import org.jboss.blog.model.XmlType;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+
+import javax.persistence.EntityManager;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("templateService")
+ at Scope(ScopeType.STATELESS)
+ at AutoCreate
+public class TemplateServiceBean {
+ @In
+ private EntityManager entityManager;
+
+ @SuppressWarnings("unchecked")
+ public List<Template> getAllTemplates() {
+ return entityManager.createQuery("select t from Template t order by t.name, t.type").getResultList();
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<org.jboss.blog.model.Template> templatesOfType(XmlType type) {
+ return entityManager.createQuery("select t from Template t where t.type = ?1 order by t.name")
+ .setParameter(1, type).getResultList();
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/xml/velocity/VelocityXmlService.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/xml/velocity/VelocityXmlService.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/xml/velocity/VelocityXmlService.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,147 @@
+package org.jboss.blog.session.xml.velocity;
+
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.XmlType;
+import org.jboss.blog.model.RestrictedPost;
+import org.jboss.blog.service.FeedsService;
+import org.jboss.blog.service.FeedNotFoundException;
+import org.jboss.blog.session.xml.XmlService;
+import org.jboss.blog.session.xml.content.ContentResponse;
+import org.jboss.blog.session.xml.content.InMemoryContentResponse;
+import org.jboss.blog.session.xml.velocity.tools.XmlTools;
+import org.jboss.blog.session.xml.velocity.tools.AtomXmlTools;
+import org.jboss.blog.session.xml.velocity.tools.Rss2XmlTools;
+import org.jboss.blog.session.xml.velocity.tools.Rss1XmlTools;
+import org.jboss.blog.session.cache.CacheManager;
+import org.jboss.blog.session.tools.PostToToolsBean;
+import org.jboss.blog.session.security.SecurityUserKeys;
+import org.jboss.blog.session.security.FeedsIdentity;
+import org.jboss.blog.session.security.Authenticator;
+import org.jboss.blog.model.security.SecurityUser;
+import org.jboss.blog.tools.GeneralTools;
+import org.jboss.seam.annotations.*;
+import org.jboss.seam.log.Log;
+import org.jboss.seam.ScopeType;
+
+import javax.annotation.PostConstruct;
+import java.util.List;
+import java.util.Properties;
+import java.util.Map;
+import java.util.HashMap;
+import java.io.CharArrayReader;
+import java.io.CharArrayWriter;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("xmlService")
+ at Scope(ScopeType.STATELESS)
+ at AutoCreate
+public class VelocityXmlService implements XmlService {
+ @In
+ private FeedsService feedsService;
+
+ @In
+ private CacheManager cacheManager;
+
+ @In
+ private PostToToolsBean postToTools;
+
+ @In
+ private SecurityUserKeys securityUserKeys;
+
+ @In
+ private Authenticator authenticator;
+
+ @In
+ private FeedsIdentity identity;
+
+ @Logger
+ private Log log;
+
+ private VelocityEngine engine;
+
+ private Map<XmlType, XmlTools> xmlTools;
+
+ @PostConstruct
+ public void initVeloctiy() {
+ xmlTools = new HashMap<XmlType, XmlTools>();
+ xmlTools.put(XmlType.ATOM, new AtomXmlTools());
+ xmlTools.put(XmlType.RSS2, new Rss2XmlTools());
+ xmlTools.put(XmlType.RSS1, new Rss1XmlTools());
+
+ try {
+ Properties props = new Properties();
+ props.load(this.getClass().getResourceAsStream("/velocity.properties"));
+
+ engine = new VelocityEngine(props);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void writeXml(String feedType, String feedName, String feedKey, ContentResponse response)
+ throws Exception {
+ InMemoryContentResponse inCache = cacheManager.getFeedXml(feedName, feedType);
+
+ if (inCache == null) {
+ inCache = new InMemoryContentResponse();
+
+ log.debug("Generating xml for feed '#0' of type: #1.", feedName, feedType);
+
+ XmlType xmlType;
+ try {
+ xmlType = XmlType.valueOf(feedType == null ? "" : feedType.toUpperCase());
+ } catch (IllegalArgumentException e) {
+ throw new InvalidTemplateTypeException(e);
+ }
+
+ Feed feed = feedsService.getFeed(feedName);
+
+ boolean isRestricted = feed.isFeedRestricted();
+ if (isRestricted) {
+ SecurityUser su = securityUserKeys.seachForSecurityUserByKey(feedKey);
+
+ if (su == null) {
+ throw new FeedNotFoundException();
+ } else {
+ // "Loggging in" the found user
+ identity.loginAs(su);
+ authenticator.flushRoles();
+ }
+ }
+
+ if (feed.getTemplates().get(xmlType) == null) {
+ throw new InvalidTemplateTypeException();
+ }
+
+ List<? extends RestrictedPost> posts = feedsService.getPosts(feed, 0, feed.getMaxPostsInFeed(), true);
+
+ inCache.setContentType(xmlType.contentType());
+ inCache.setCharacterEncoding("utf-8");
+
+ VelocityContext context = new VelocityContext();
+ context.put("posts", posts);
+ context.put("feed", feed);
+ context.put("tools", xmlTools.get(xmlType));
+ context.put("xmlType", xmlType);
+ context.put("postToTools", postToTools);
+
+ Template template = engine.getTemplate(feed.getTemplates().get(xmlType).getName());
+ template.merge(context, inCache.getWriter());
+
+ if (!isRestricted) {
+ cacheManager.putFeedXml(feedName, feedType, inCache);
+ }
+ }
+
+ response.setCharacterEncoding(inCache.getCharacterEncoding());
+ response.setContentType(inCache.getContentType());
+
+ GeneralTools.transfer(new CharArrayReader(((CharArrayWriter) inCache.getWriter()).toCharArray()),
+ response.getWriter());
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/xml/velocity/tools/AtomXmlTools.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/xml/velocity/tools/AtomXmlTools.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/xml/velocity/tools/AtomXmlTools.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,16 @@
+package org.jboss.blog.session.xml.velocity.tools;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class AtomXmlTools extends XmlTools {
+ public String formatDate(Date date) {
+ String noZoneDate = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").format(date);
+ String zone = new SimpleDateFormat("Z").format(date);
+
+ return noZoneDate + zone.substring(0, 3) + ":" + zone.substring(3, 5);
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/xml/velocity/tools/Rss1XmlTools.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/xml/velocity/tools/Rss1XmlTools.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/xml/velocity/tools/Rss1XmlTools.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,13 @@
+package org.jboss.blog.session.xml.velocity.tools;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class Rss1XmlTools extends XmlTools {
+ public String formatDate(Date date) {
+ return new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z").format(date);
+ }
+}
\ No newline at end of file
Added: feeds100P26/src/action/org/jboss/blog/session/xml/velocity/tools/Rss2XmlTools.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/xml/velocity/tools/Rss2XmlTools.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/xml/velocity/tools/Rss2XmlTools.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,13 @@
+package org.jboss.blog.session.xml.velocity.tools;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class Rss2XmlTools extends XmlTools {
+ public String formatDate(Date date) {
+ return new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z").format(date);
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/session/xml/velocity/tools/XmlTools.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/session/xml/velocity/tools/XmlTools.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/session/xml/velocity/tools/XmlTools.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,53 @@
+package org.jboss.blog.session.xml.velocity.tools;
+
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.Post;
+import org.jboss.blog.model.XmlType;
+import org.jboss.blog.service.LinkService;
+import org.jboss.blog.tools.StringTools;
+import org.jboss.seam.Component;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class XmlTools {
+ public String formatDate(Date date) {
+ return new SimpleDateFormat("MM/dd/yy").format(date);
+ }
+
+ public Date feedPubDate(Feed feed, List<Post> posts) {
+ if (posts.size() != 0) {
+ return posts.get(0).getPublished();
+ }
+
+ Calendar cal = Calendar.getInstance();
+ cal.setTimeInMillis(0);
+
+ return cal.getTime();
+ }
+
+ public String escape(String toEscape) {
+ return StringTools.escape(toEscape);
+ }
+
+ private LinkService getLinkService() {
+ return (LinkService) Component.getInstance("linkService");
+ }
+
+ public String feedPageLink(Feed feed) {
+ return getLinkService().generateFeedPageLink(feed);
+ }
+
+ public String feedLink(Feed feed, XmlType type) {
+ return getLinkService().generateFeedLink(feed, type);
+ }
+
+ public String postLink(Post post) {
+ return getLinkService().generatePostLink(post);
+ }
+}
Added: feeds100P26/src/action/org/jboss/blog/tools/PostFilterTools.java
===================================================================
--- feeds100P26/src/action/org/jboss/blog/tools/PostFilterTools.java (rev 0)
+++ feeds100P26/src/action/org/jboss/blog/tools/PostFilterTools.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,33 @@
+package org.jboss.blog.tools;
+
+import org.jboss.blog.model.RestrictedPost;
+import org.jboss.blog.model.post.PostFilter;
+
+import java.util.List;
+import java.util.Iterator;
+import java.util.ArrayList;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class PostFilterTools {
+ public static void filterFromPostList(List<? extends RestrictedPost> posts, PostFilter filter) {
+ for (Iterator<? extends RestrictedPost> iter = posts.iterator(); iter.hasNext();) {
+ if (!filter.filter(iter.next())) {
+ iter.remove();
+ }
+ }
+ }
+
+ public static <T extends RestrictedPost> List<T> filterPostList(List<T> posts, PostFilter filter) {
+ List<T> filtered = new ArrayList<T>();
+
+ for (T post : posts) {
+ if (filter.filter(post)) {
+ filtered.add(post);
+ }
+ }
+
+ return filtered;
+ }
+}
Added: feeds100P26/src/action/org/jboss/shotoku/web/FilesystemResourceResolver.java
===================================================================
--- feeds100P26/src/action/org/jboss/shotoku/web/FilesystemResourceResolver.java (rev 0)
+++ feeds100P26/src/action/org/jboss/shotoku/web/FilesystemResourceResolver.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,32 @@
+package org.jboss.shotoku.web;
+
+import com.sun.facelets.impl.ResourceResolver;
+
+import javax.faces.context.FacesContext;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class FilesystemResourceResolver implements ResourceResolver {
+ private String sourceBasePath;
+
+ public String getSourceBasePath() {
+ if (sourceBasePath == null) {
+ sourceBasePath = FacesContext.getCurrentInstance().getExternalContext()
+ .getInitParameter("sourceBasePath");
+ }
+
+ return sourceBasePath;
+ }
+
+ public URL resolveUrl(String s) {
+ try {
+ return new URL("file", "", getSourceBasePath() + s);
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+}
Added: feeds100P26/src/action/org/jboss/shotoku/web/ResourcesFilter.java
===================================================================
--- feeds100P26/src/action/org/jboss/shotoku/web/ResourcesFilter.java (rev 0)
+++ feeds100P26/src/action/org/jboss/shotoku/web/ResourcesFilter.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,189 @@
+/******************************************************************************
+ * JBoss, a division of Red Hat *
+ * Copyright 2006, Red Hat Middleware, LLC, and individual *
+ * contributors as indicated by the @authors tag. See the *
+ * copyright.txt in the distribution for a full listing of *
+ * individual contributors. *
+ * *
+ * This is free software; you can redistribute it and/or modify it *
+ * under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation; either version 2.1 of *
+ * the License, or (at your option) any later version. *
+ * *
+ * This software is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with this software; if not, write to the Free *
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org. *
+ ******************************************************************************/
+package org.jboss.shotoku.web;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import java.io.*;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Arrays;
+import java.util.logging.Logger;
+
+/**
+ * A filter, which reads resources from the filesystem and makes them visible to the
+ * application as deployed files --- useful for development. Specifically,
+ * the <code>sourceBasePath</code> init-parameter value
+ * is prepended to the path. The file referenced by the path is then included
+ * in the request. To specify for which file extensions the filter is enabled,
+ * set the <code>extensions</code> init parameter. If not set, it defaults to:
+ * <code>jsp,css,html,htm,gif,jpg,jpeg,png,txt,xhtml</code>.
+ *
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class ResourcesFilter implements Filter {
+ private final static Logger log = Logger.getLogger(ResourcesFilter.class.getName());
+
+ /**
+ * A list of extensions, which are filtered by default, if nothing is
+ * specified in the filter configuration.
+ */
+ private final static String DEFAULT_EXTENSIONS = "jsp,css,html,htm,gif,jpg,jpeg,png,txt,xhtml";
+
+ /**
+ * Base path to a directory where files will
+ * be copied; it's a subdirectory of a deployment directory created by the
+ * app server.
+ */
+ private String destBasePath;
+
+ /**
+ * Directory in the filesystem from which to read the files.
+ */
+ private String sourceBasePath;
+
+ /**
+ * A set of <code>java.lang.String</code>s, which are extensions, that are filtered.
+ */
+ private Set<String> extensions;
+
+ /**
+ * Transfers all bytes from the given input stream to the given output
+ * stream.
+ *
+ * @param is
+ * Input stream to read from.
+ * @param os
+ * Output stream to write to.
+ * @throws java.io.IOException In case of an IO exception.
+ */
+ private void transfer(InputStream is, OutputStream os) throws IOException {
+ byte[] buffer = new byte[1024];
+ int read;
+ while ((read = is.read(buffer)) != -1) {
+ os.write(buffer, 0, read);
+ }
+ }
+
+ public void init(FilterConfig conf) {
+ sourceBasePath = conf.getInitParameter("sourceBasePath");
+ if (sourceBasePath == null || "".equals(sourceBasePath)) {
+ sourceBasePath = conf.getServletContext().getInitParameter("sourceBasePath");
+ }
+
+ destBasePath = conf.getServletContext().getRealPath("");
+
+ extensions = new HashSet<String>();
+ String filteredExtensionsString = conf.getInitParameter("extensions");
+
+ if (filteredExtensionsString == null) {
+ filteredExtensionsString = DEFAULT_EXTENSIONS;
+ }
+
+ String[] tokens = filteredExtensionsString.split(",");
+
+ extensions.addAll(Arrays.asList(tokens));
+ }
+
+ private String safeToString(Object o) {
+ if (o == null) {
+ return null;
+ }
+
+ return o.toString();
+ }
+
+ private boolean checkExtension(String path) {
+ int dotIndex = path.lastIndexOf('.');
+
+ if (dotIndex != -1) {
+ String extension = path.substring(dotIndex + 1);
+ return extensions.contains(extension);
+ } else {
+ return false;
+ }
+ }
+
+ public void doFilter(ServletRequest request, ServletResponse response,
+ FilterChain chain) throws IOException, ServletException {
+ if (request instanceof HttpServletRequest) {
+ HttpServletRequest httpRequest = (HttpServletRequest) request;
+
+ /* Getting the name of the requested resource; first checking if
+ * it is an included, then forwarded resource. Finally, checking
+ * the request uri itself. */
+ String requestedResource;
+ requestedResource = safeToString(httpRequest.getAttribute("javax.servlet.include.servlet_path"));
+
+ if (requestedResource == null) {
+ requestedResource = httpRequest.getServletPath();
+ }
+
+ // JSF check - we have to replace .jsf with .jsp.
+ String realRequestedResource = requestedResource;
+ if (realRequestedResource.endsWith(".jsf")) {
+ realRequestedResource = realRequestedResource.replace(".jsf", ".jsp");
+ } else if (realRequestedResource.endsWith(".seam")) {
+ realRequestedResource = realRequestedResource.replace(".seam", ".xhtml");
+ }
+
+ // Filtering only some file extensions. Not filtering Seam's debug.xhtml.
+ if ((!checkExtension(realRequestedResource)) || (realRequestedResource.indexOf("debug.xhtml") != -1)) {
+ chain.doFilter(request, response);
+ return;
+ }
+
+ File sourceFile = new File(sourceBasePath + realRequestedResource);
+ File destFile = new File(destBasePath + realRequestedResource);
+
+ InputStream in = null;
+ OutputStream out = null;
+
+ try {
+ destFile.getParentFile().mkdirs();
+ destFile.setLastModified(System.currentTimeMillis());
+
+ in = new FileInputStream(sourceFile);
+ out = new FileOutputStream(destFile);
+
+ transfer(in, out);
+ } catch (Exception e) {
+ log.warning("Cannot copy resource: " + sourceFile);
+ } finally {
+ if (in != null) {
+ in.close();
+ }
+
+ if (out != null) {
+ out.close();
+ }
+ }
+ }
+
+ chain.doFilter(request, response);
+ }
+
+ public void destroy() {
+
+ }
+}
\ No newline at end of file
Added: feeds100P26/src/model/org/jboss/blog/model/Category.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/Category.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/Category.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,73 @@
+package org.jboss.blog.model;
+
+import org.hibernate.validator.NotEmpty;
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.CacheConcurrencyStrategy;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Entity
+ at Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
+public class Category implements RestrictedCategory {
+ @Id
+ @GeneratedValue
+ @Column(updatable = false)
+ private Integer id;
+
+ @NotEmpty
+ @Column(unique = true)
+ private String name;
+
+ public Category(String name) {
+ this.name = name;
+ }
+
+ public Category() {
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof Category)) return false;
+
+ Category category = (Category) o;
+
+ if (id != null ? !id.equals(category.id) : category.id != null) return false;
+ if (name != null ? !name.equals(category.name) : category.name != null) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ int result;
+ result = (id != null ? id.hashCode() : 0);
+ result = 31 * result + (name != null ? name.hashCode() : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}
Added: feeds100P26/src/model/org/jboss/blog/model/Enclosure.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/Enclosure.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/Enclosure.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,105 @@
+package org.jboss.blog.model;
+
+import org.hibernate.validator.NotEmpty;
+import org.hibernate.validator.Length;
+import org.hibernate.validator.NotNull;
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.CacheConcurrencyStrategy;
+
+import javax.persistence.*;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Entity
+ at Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
+public class Enclosure implements RestrictedEnclosure {
+ @Id
+ @GeneratedValue
+ @Column(updatable = false)
+ private Integer id;
+
+ @ManyToOne(optional = false, fetch = FetchType.LAZY)
+ @NotNull
+ private Post post;
+
+ @NotEmpty
+ @Length(max = 512)
+ private String url;
+
+ @Column
+ @NotNull
+ private long length;
+
+ @Length(max = 128)
+ @NotNull
+ private String type;
+
+ public Enclosure() { }
+
+ public Enclosure(Post post, String url, long length, String type) {
+ this.post = post;
+ this.url = url;
+ this.length = length;
+ this.type = type;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public Post getPost() {
+ return post;
+ }
+
+ public void setPost(Post post) {
+ this.post = post;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public long getLength() {
+ return length;
+ }
+
+ public void setLength(long length) {
+ this.length = length;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof Enclosure)) return false;
+
+ Enclosure enclosure = (Enclosure) o;
+
+ if (id != null ? !id.equals(enclosure.id) : enclosure.id != null) return false;
+ if (url != null ? !url.equals(enclosure.url) : enclosure.url != null) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ int result;
+ result = (id != null ? id.hashCode() : 0);
+ result = 31 * result + (url != null ? url.hashCode() : 0);
+ return result;
+ }
+}
Added: feeds100P26/src/model/org/jboss/blog/model/Group.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/Group.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/Group.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,99 @@
+package org.jboss.blog.model;
+
+import org.hibernate.validator.NotEmpty;
+import org.hibernate.validator.Pattern;
+import org.hibernate.validator.Length;
+import org.hibernate.validator.Email;
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.CacheConcurrencyStrategy;
+
+import javax.persistence.*;
+import java.io.Serializable;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Entity
+ at Table(name = "FeedGroup")
+ at Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
+public class Group implements Serializable {
+ @Id
+ @GeneratedValue
+ @Column(updatable = false)
+ private Integer id;
+
+ @NotEmpty
+ @Column(unique = true)
+ @Length(max = 32)
+ @Pattern(regex = "^[a-z0-9_]*$", message = "#{messages['blog.group.invalidname']}")
+ private String name;
+
+ @NotEmpty
+ @Length(max = 64)
+ private String displayName;
+
+ @Lob
+ private String header;
+
+ @Email
+ private String adminEmail;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public void setDisplayName(String displayName) {
+ this.displayName = displayName;
+ }
+
+ public String getHeader() {
+ return header;
+ }
+
+ public void setHeader(String header) {
+ this.header = header;
+ }
+
+ public String getAdminEmail() {
+ return adminEmail;
+ }
+
+ public void setAdminEmail(String adminEmail) {
+ this.adminEmail = adminEmail;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof Group)) return false;
+
+ Group group = (Group) o;
+
+ if (id != null ? !id.equals(group.id) : group.id != null) return false;
+ if (name != null ? !name.equals(group.name) : group.name != null) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ int result;
+ result = (id != null ? id.hashCode() : 0);
+ result = 31 * result + (name != null ? name.hashCode() : 0);
+ return result;
+ }
+}
Added: feeds100P26/src/model/org/jboss/blog/model/Image.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/Image.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/Image.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,101 @@
+package org.jboss.blog.model;
+
+import org.hibernate.validator.NotEmpty;
+import org.hibernate.validator.Length;
+import org.hibernate.validator.NotNull;
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.CacheConcurrencyStrategy;
+
+import javax.persistence.*;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Entity
+ at Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
+public class Image implements RestrictedImage {
+ @Id
+ @GeneratedValue
+ @Column(updatable = false)
+ private Integer id;
+
+ @ManyToOne(optional = false, fetch = FetchType.LAZY)
+ @NotNull
+ private Post post;
+
+ @NotEmpty
+ @Length(max = 512)
+ private String url;
+
+ @Length(max = 512)
+ private String title;
+
+ @Length(max = 512)
+ private String link;
+
+ public Image() { }
+
+ public Image(Post post, String url) {
+ this.post = post;
+ this.url = url;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public Post getPost() {
+ return post;
+ }
+
+ public void setPost(Post post) {
+ this.post = post;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getLink() {
+ return link;
+ }
+
+ public void setLink(String link) {
+ this.link = link;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof Image)) return false;
+
+ Image image = (Image) o;
+
+ if (id != null ? !id.equals(image.id) : image.id != null) return false;
+ if (url != null ? !url.equals(image.url) : image.url != null) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ int result;
+ result = (id != null ? id.hashCode() : 0);
+ result = 31 * result + (url != null ? url.hashCode() : 0);
+ return result;
+ }
+}
Added: feeds100P26/src/model/org/jboss/blog/model/Post.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/Post.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/Post.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,230 @@
+package org.jboss.blog.model;
+
+import org.hibernate.search.annotations.*;
+import org.hibernate.validator.Length;
+import org.hibernate.validator.NotEmpty;
+import org.hibernate.validator.NotNull;
+import org.hibernate.validator.Pattern;
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.CacheConcurrencyStrategy;
+import org.jboss.blog.tools.search.bridge.StripHtmlBridge;
+import org.jboss.blog.tools.search.bridge.FeedBridge;
+import org.jboss.blog.tools.search.UnrestrictedFeedFilter;
+import org.jboss.blog.tools.StringTools;
+import org.jboss.blog.tools.GeneralTools;
+import org.jboss.blog.model.feed.Feed;
+
+import javax.persistence.*;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Entity
+ at Indexed
+ at Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
+ at FullTextFilterDef(name = "unrestrictedFeedFilter", impl = UnrestrictedFeedFilter.class)
+public class Post implements RestrictedPost {
+ @Id
+ @GeneratedValue
+ @Column(updatable = false)
+ @DocumentId
+ private Integer id;
+
+ @NotEmpty
+ @Length(max = 512)
+ @Field
+ @Boost(2)
+ private String title;
+
+ @NotEmpty
+ @Pattern(regex = "^[a-z0-9_]*$")
+ @Column(unique = true)
+ private String titleAsId;
+
+ @Lob
+ @Field(bridge = @FieldBridge(impl = StripHtmlBridge.class))
+ private String content;
+
+ @Length(max = 512)
+ @NotEmpty
+ private String link;
+
+ @Length(max = 256)
+ @Field
+ private String author;
+
+ @ManyToMany
+ @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
+ private List<Category> categories;
+
+ @Temporal(value = TemporalType.TIMESTAMP)
+ @NotNull
+ private Date published;
+
+ @Temporal(value = TemporalType.TIMESTAMP)
+ @NotNull
+ private Date modified;
+
+ @OneToMany(mappedBy = "post", cascade = CascadeType.ALL)
+ @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
+ private List<Enclosure> enclosures;
+
+ @OneToMany(mappedBy = "post", cascade = CascadeType.ALL)
+ @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
+ private List<Image> images;
+
+ @ManyToOne
+ @NotNull
+ @Field(name = "restricted", bridge = @FieldBridge(impl = FeedBridge.class))
+ private Feed feed;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ setTitleAsId(StringTools.convertTitleToLink(title));
+ this.title = title;
+ }
+
+ public String getTitleAsId() {
+ return titleAsId;
+ }
+
+ public void setTitleAsId(String titleAsId) {
+ this.titleAsId = titleAsId;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public void setContent(String content) {
+ this.content = content;
+ }
+
+ public String getLink() {
+ return link;
+ }
+
+ public void setLink(String link) {
+ this.link = link;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public void setAuthor(String author) {
+ this.author = author;
+ }
+
+ public List<Category> getCategories() {
+ return categories;
+ }
+
+ public void setCategories(List<Category> categories) {
+ this.categories = categories;
+ }
+
+ public Date getPublished() {
+ return published;
+ }
+
+ public void setPublished(Date published) {
+ this.published = published;
+ }
+
+ public Date getModified() {
+ return modified;
+ }
+
+ public void setModified(Date modified) {
+ this.modified = modified;
+ }
+
+ public List<Enclosure> getEnclosures() {
+ return enclosures;
+ }
+
+ public void setEnclosures(List<Enclosure> enclosures) {
+ this.enclosures = enclosures;
+ }
+
+ public List<Image> getImages() {
+ return images;
+ }
+
+ public void setImages(List<Image> images) {
+ this.images = images;
+ }
+
+ public Feed getFeed() {
+ return feed;
+ }
+
+ public void setFeed(Feed feed) {
+ this.feed = feed;
+ }
+
+ @Transient
+ public String getEffectiveAuthor() {
+ String postAuthor = getAuthor();
+ switch (getFeed().getPostAuthorType()) {
+ case POST_AUTHOR:
+ return postAuthor == null ? "" : postAuthor;
+
+ case BLOG_AUTHOR:
+ return getFeed().getAuthor();
+
+ case BLOG_AUTHOR_IF_MISSING:
+ return StringTools.isEmpty(postAuthor) ? getFeed().getAuthor() : postAuthor;
+ }
+
+ return null;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof Post)) return false;
+
+ Post post = (Post) o;
+
+ if (id != null ? !id.equals(post.id) : post.id != null) return false;
+ if (title != null ? !title.equals(post.title) : post.title != null) return false;
+ if (titleAsId != null ? !titleAsId.equals(post.titleAsId) : post.titleAsId != null) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ int result;
+ result = (id != null ? id.hashCode() : 0);
+ result = 31 * result + (title != null ? title.hashCode() : 0);
+ result = 31 * result + (titleAsId != null ? titleAsId.hashCode() : 0);
+ return result;
+ }
+
+ public int compareTo(RestrictedPost post2) {
+ int result = - GeneralTools.compareDates(getPublished(), post2.getPublished());
+ if (result == 0) {
+ return GeneralTools.compareStrings(getTitle(), post2.getTitle());
+ } else {
+ return result;
+ }
+ }
+
+ public String toString() {
+ return "Post(title = " + title + ", published = " + published + ", titleAsId = " + titleAsId + ")";
+ }
+}
Added: feeds100P26/src/model/org/jboss/blog/model/RestrictedCategory.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/RestrictedCategory.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/RestrictedCategory.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,12 @@
+package org.jboss.blog.model;
+
+import java.io.Serializable;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public interface RestrictedCategory extends Serializable {
+ Integer getId();
+
+ String getName();
+}
Added: feeds100P26/src/model/org/jboss/blog/model/RestrictedEnclosure.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/RestrictedEnclosure.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/RestrictedEnclosure.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,16 @@
+package org.jboss.blog.model;
+
+import java.io.Serializable;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public interface RestrictedEnclosure extends Serializable {
+ Integer getId();
+
+ String getUrl();
+
+ long getLength();
+
+ String getType();
+}
Added: feeds100P26/src/model/org/jboss/blog/model/RestrictedImage.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/RestrictedImage.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/RestrictedImage.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,14 @@
+package org.jboss.blog.model;
+
+import java.io.Serializable;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public interface RestrictedImage extends Serializable {
+ Integer getId();
+
+ String getUrl();
+
+ String getTitle();
+}
Added: feeds100P26/src/model/org/jboss/blog/model/RestrictedPost.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/RestrictedPost.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/RestrictedPost.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,38 @@
+package org.jboss.blog.model;
+
+import org.jboss.blog.model.feed.RestrictedFeed;
+
+import java.util.List;
+import java.util.Date;
+import java.io.Serializable;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public interface RestrictedPost extends Comparable<RestrictedPost>, Serializable {
+ Integer getId();
+
+ String getTitle();
+
+ String getTitleAsId();
+
+ String getContent();
+
+ String getLink();
+
+ String getAuthor();
+
+ List<? extends RestrictedCategory> getCategories();
+
+ Date getPublished();
+
+ Date getModified();
+
+ List<? extends RestrictedEnclosure> getEnclosures();
+
+ List<? extends RestrictedImage> getImages();
+
+ RestrictedFeed getFeed();
+
+ String getEffectiveAuthor();
+}
Added: feeds100P26/src/model/org/jboss/blog/model/Template.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/Template.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/Template.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,104 @@
+package org.jboss.blog.model;
+
+import org.hibernate.validator.Length;
+import org.hibernate.validator.NotEmpty;
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.CacheConcurrencyStrategy;
+
+import javax.persistence.*;
+import java.util.Date;
+import java.io.Serializable;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Entity
+ at Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
+public class Template implements Serializable {
+ @Id
+ @GeneratedValue
+ @Column(updatable = false)
+ private Integer id;
+
+ @Length(max = 32)
+ @NotEmpty
+ @Column(unique = true)
+ private String name;
+
+ @Lob
+ @NotEmpty
+ private String text;
+
+ @Enumerated
+ private XmlType type;
+
+ @Temporal(value = TemporalType.TIMESTAMP)
+ private Date lastModified;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ public XmlType getType() {
+ return type;
+ }
+
+ public void setType(XmlType type) {
+ this.type = type;
+ }
+
+ public Date getLastModified() {
+ return lastModified;
+ }
+
+ public void setLastModified(Date lastModified) {
+ this.lastModified = lastModified;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof Template)) return false;
+
+ Template template = (Template) o;
+
+ if (type != template.type) return false;
+ if (id != null ? !id.equals(template.id) : template.id != null) return false;
+ if (name != null ? !name.equals(template.name) : template.name != null) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ int result;
+ result = (id != null ? id.hashCode() : 0);
+ result = 31 * result + (name != null ? name.hashCode() : 0);
+ result = 31 * result + (type != null ? type.hashCode() : 0);
+ return result;
+ }
+
+ @PrePersist
+ @PreUpdate
+ public void updateLastModified() {
+ setLastModified(new Date());
+ }
+}
Added: feeds100P26/src/model/org/jboss/blog/model/XmlType.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/XmlType.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/XmlType.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,20 @@
+package org.jboss.blog.model;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public enum XmlType {
+ ATOM("application/atom+xml"),
+ RSS2("application/xhtml+xml"),
+ RSS1("application/xhtml+xml");
+
+ private final String contentType;
+
+ public String contentType() {
+ return contentType;
+ }
+
+ XmlType(String contentType) {
+ this.contentType = contentType;
+ }
+}
Added: feeds100P26/src/model/org/jboss/blog/model/configuration/Configuration.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/configuration/Configuration.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/configuration/Configuration.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,99 @@
+package org.jboss.blog.model.configuration;
+
+import org.hibernate.validator.NotNull;
+import org.hibernate.validator.Email;
+
+import javax.persistence.*;
+import java.io.Serializable;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Entity
+public class Configuration implements Serializable {
+ @Id
+ @GeneratedValue
+ @Column(updatable = false)
+ private Integer id;
+
+ @Column
+ @NotNull
+ private int readTimeout;
+
+ @Column
+ @NotNull
+ private int connectionTimeout;
+
+ @Column
+ @NotNull
+ private int updateInterval;
+
+ @Column
+ @Email
+ private String adminEmail;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public int getReadTimeout() {
+ return readTimeout;
+ }
+
+ public void setReadTimeout(int readTimeout) {
+ this.readTimeout = readTimeout;
+ }
+
+ public int getConnectionTimeout() {
+ return connectionTimeout;
+ }
+
+ public void setConnectionTimeout(int connectionTimeout) {
+ this.connectionTimeout = connectionTimeout;
+ }
+
+ public int getUpdateInterval() {
+ return updateInterval;
+ }
+
+ public void setUpdateInterval(int updateInterval) {
+ this.updateInterval = updateInterval;
+ }
+
+ public String getAdminEmail() {
+ return adminEmail;
+ }
+
+ public void setAdminEmail(String adminEmail) {
+ this.adminEmail = adminEmail;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof Configuration)) return false;
+
+ Configuration that = (Configuration) o;
+
+ if (connectionTimeout != that.connectionTimeout) return false;
+ if (readTimeout != that.readTimeout) return false;
+ if (updateInterval != that.updateInterval) return false;
+ if (adminEmail != null ? !adminEmail.equals(that.adminEmail) : that.adminEmail != null) return false;
+ if (id != null ? !id.equals(that.id) : that.id != null) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ int result;
+ result = (id != null ? id.hashCode() : 0);
+ result = 31 * result + readTimeout;
+ result = 31 * result + connectionTimeout;
+ result = 31 * result + updateInterval;
+ result = 31 * result + (adminEmail != null ? adminEmail.hashCode() : 0);
+ return result;
+ }
+}
Added: feeds100P26/src/model/org/jboss/blog/model/feed/AggregatedFeed.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/feed/AggregatedFeed.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/feed/AggregatedFeed.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,62 @@
+package org.jboss.blog.model.feed;
+
+import org.jboss.blog.model.post.PostFilter;
+import org.jboss.blog.model.Group;
+import org.hibernate.validator.NotNull;
+import org.hibernate.annotations.CollectionOfElements;
+import org.hibernate.annotations.MapKeyManyToMany;
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.CacheConcurrencyStrategy;
+
+import javax.persistence.Entity;
+import javax.persistence.Basic;
+import javax.persistence.Lob;
+import java.util.Map;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Entity
+ at Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
+public class AggregatedFeed extends Feed {
+ @CollectionOfElements
+ @MapKeyManyToMany
+ @Lob
+ @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
+ private Map<Feed, PostFilter> feeds;
+
+ @CollectionOfElements
+ @MapKeyManyToMany
+ @Lob
+ @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
+ private Map<Group, PostFilter> groups;
+
+ @NotNull
+ @Basic
+ @Lob
+ private PostFilter globalFilter;
+
+ public Map<Feed, PostFilter> getFeeds() {
+ return feeds;
+ }
+
+ public void setFeeds(Map<Feed, PostFilter> feeds) {
+ this.feeds = feeds;
+ }
+
+ public Map<Group, PostFilter> getGroups() {
+ return groups;
+ }
+
+ public void setGroups(Map<Group, PostFilter> groups) {
+ this.groups = groups;
+ }
+
+ public PostFilter getGlobalFilter() {
+ return globalFilter;
+ }
+
+ public void setGlobalFilter(PostFilter globalFilter) {
+ this.globalFilter = globalFilter;
+ }
+}
Added: feeds100P26/src/model/org/jboss/blog/model/feed/Feed.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/feed/Feed.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/feed/Feed.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,261 @@
+package org.jboss.blog.model.feed;
+
+import org.hibernate.validator.Length;
+import org.hibernate.validator.NotEmpty;
+import org.hibernate.validator.Pattern;
+import org.hibernate.validator.NotNull;
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.CacheConcurrencyStrategy;
+import org.jboss.blog.model.Post;
+import org.jboss.blog.model.XmlType;
+import org.jboss.blog.model.Template;
+import org.jboss.blog.model.Group;
+
+import javax.persistence.*;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Entity
+ at Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
+ at Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
+public class Feed implements RestrictedFeed {
+ @Id
+ @GeneratedValue(strategy = GenerationType.TABLE)
+ @Column(updatable = false)
+ private Integer id;
+
+ @NotNull
+ @ManyToOne
+ private Group group;
+
+ @NotEmpty
+ @Length(max = 32)
+ @Column(unique = true)
+ @Pattern(regex = "^[a-z0-9_]*$", message = "#{messages['blog.feed.new.invalidname']}")
+ private String name;
+
+ @NotEmpty
+ @Length(max = 512)
+ private String title;
+
+ @NotEmpty
+ @Length(max = 256)
+ private String author;
+
+ @Length(max = 512)
+ private String link;
+
+ @OneToMany(cascade = {CascadeType.REMOVE}, mappedBy = "feed")
+ private List<Post> posts;
+
+ @Lob
+ private String description;
+
+ @ManyToMany
+ @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
+ private Map<XmlType, Template> templates;
+
+ @Column
+ private int maxPostsInFeed;
+
+ @Column
+ private int maxPostsOnPage;
+
+ @Column
+ @NotNull
+ private PostAuthorType postAuthorType;
+
+ @Column
+ @NotNull
+ private boolean accepted;
+
+ @Column
+ private Boolean showDigg;
+
+ @Column
+ private Boolean showDzone;
+
+ @Column
+ private Boolean showDelicious;
+
+ @Column
+ private Boolean showStumble;
+
+ @Column
+ private Boolean restricted;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public Group getGroup() {
+ return group;
+ }
+
+ public void setGroup(Group group) {
+ this.group = group;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public void setAuthor(String author) {
+ this.author = author;
+ }
+
+ public String getLink() {
+ return link;
+ }
+
+ public void setLink(String link) {
+ this.link = link;
+ }
+
+ public List<Post> getPosts() {
+ return posts;
+ }
+
+ public void setPosts(List<Post> posts) {
+ this.posts = posts;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public Map<XmlType, Template> getTemplates() {
+ return templates;
+ }
+
+ public void setTemplates(Map<XmlType, Template> templates) {
+ this.templates = templates;
+ }
+
+ public int getMaxPostsInFeed() {
+ return maxPostsInFeed;
+ }
+
+ public void setMaxPostsInFeed(int maxPostsInFeed) {
+ this.maxPostsInFeed = maxPostsInFeed;
+ }
+
+ public int getMaxPostsOnPage() {
+ return maxPostsOnPage;
+ }
+
+ public void setMaxPostsOnPage(int maxPostsOnPage) {
+ this.maxPostsOnPage = maxPostsOnPage;
+ }
+
+ public PostAuthorType getPostAuthorType() {
+ return postAuthorType;
+ }
+
+ public void setPostAuthorType(PostAuthorType postAuthorType) {
+ this.postAuthorType = postAuthorType;
+ }
+
+ public boolean isAccepted() {
+ return accepted;
+ }
+
+ public void setAccepted(boolean accepted) {
+ this.accepted = accepted;
+ }
+
+ public Boolean getShowDigg() {
+ return showDigg;
+ }
+
+ public void setShowDigg(Boolean showDigg) {
+ this.showDigg = showDigg;
+ }
+
+ public Boolean getShowDzone() {
+ return showDzone;
+ }
+
+ public void setShowDzone(Boolean showDzone) {
+ this.showDzone = showDzone;
+ }
+
+ public Boolean getShowDelicious() {
+ return showDelicious;
+ }
+
+ public void setShowDelicious(Boolean showDelicious) {
+ this.showDelicious = showDelicious;
+ }
+
+ public Boolean getShowStumble() {
+ return showStumble;
+ }
+
+ public void setShowStumble(Boolean showStumble) {
+ this.showStumble = showStumble;
+ }
+
+ public Boolean getRestricted() {
+ return restricted;
+ }
+
+ public void setRestricted(Boolean restricted) {
+ this.restricted = restricted;
+ }
+
+ @Transient
+ public boolean isFeedRestricted() {
+ if (restricted == null || !restricted) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof Feed)) return false;
+
+ Feed feed = (Feed) o;
+
+ if (id != null ? !id.equals(feed.id) : feed.id != null) return false;
+ if (name != null ? !name.equals(feed.name) : feed.name != null) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ int result;
+ result = (id != null ? id.hashCode() : 0);
+ result = 31 * result + (name != null ? name.hashCode() : 0);
+ return result;
+ }
+}
Added: feeds100P26/src/model/org/jboss/blog/model/feed/HighlightsFeed.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/feed/HighlightsFeed.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/feed/HighlightsFeed.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,27 @@
+package org.jboss.blog.model.feed;
+
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.CacheConcurrencyStrategy;
+import org.jboss.blog.model.Post;
+
+import javax.persistence.Entity;
+import javax.persistence.ManyToMany;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Entity
+ at Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
+public class HighlightsFeed extends Feed {
+ @ManyToMany
+ private List<Post> selectedPosts;
+
+ public List<Post> getSelectedPosts() {
+ return selectedPosts;
+ }
+
+ public void setSelectedPosts(List<Post> selectedPosts) {
+ this.selectedPosts = selectedPosts;
+ }
+}
Added: feeds100P26/src/model/org/jboss/blog/model/feed/IndividualPostInfo.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/feed/IndividualPostInfo.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/feed/IndividualPostInfo.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,73 @@
+package org.jboss.blog.model.feed;
+
+import org.jboss.blog.model.Post;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.GeneratedValue;
+import javax.persistence.ManyToOne;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Entity
+public class IndividualPostInfo {
+ @Id
+ @GeneratedValue
+ private int id;
+
+ @ManyToOne
+ private IndividualPostsFeed feed;
+
+ @ManyToOne
+ private Post post;
+
+ private String remoteFeedAddress;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public IndividualPostsFeed getFeed() {
+ return feed;
+ }
+
+ public void setFeed(IndividualPostsFeed feed) {
+ this.feed = feed;
+ }
+
+ public Post getPost() {
+ return post;
+ }
+
+ public void setPost(Post post) {
+ this.post = post;
+ }
+
+ public String getRemoteFeedAddress() {
+ return remoteFeedAddress;
+ }
+
+ public void setRemoteFeedAddress(String remoteFeedAddress) {
+ this.remoteFeedAddress = remoteFeedAddress;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof IndividualPostInfo)) return false;
+
+ IndividualPostInfo that = (IndividualPostInfo) o;
+
+ if (id != that.id) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ return id;
+ }
+}
Added: feeds100P26/src/model/org/jboss/blog/model/feed/IndividualPostsFeed.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/feed/IndividualPostsFeed.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/feed/IndividualPostsFeed.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,27 @@
+package org.jboss.blog.model.feed;
+
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.CacheConcurrencyStrategy;
+
+import javax.persistence.Entity;
+import javax.persistence.OneToMany;
+import javax.persistence.CascadeType;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Entity
+ at Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
+public class IndividualPostsFeed extends Feed {
+ @OneToMany(mappedBy = "feed", cascade = CascadeType.ALL)
+ private List<IndividualPostInfo> postInfos;
+
+ public List<IndividualPostInfo> getPostInfos() {
+ return postInfos;
+ }
+
+ public void setPostInfos(List<IndividualPostInfo> postInfos) {
+ this.postInfos = postInfos;
+ }
+}
\ No newline at end of file
Added: feeds100P26/src/model/org/jboss/blog/model/feed/PostAuthorType.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/feed/PostAuthorType.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/feed/PostAuthorType.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,10 @@
+package org.jboss.blog.model.feed;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public enum PostAuthorType {
+ BLOG_AUTHOR_IF_MISSING,
+ POST_AUTHOR,
+ BLOG_AUTHOR
+}
Added: feeds100P26/src/model/org/jboss/blog/model/feed/RemoteFeed.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/feed/RemoteFeed.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/feed/RemoteFeed.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,65 @@
+package org.jboss.blog.model.feed;
+
+import org.hibernate.validator.Length;
+import org.hibernate.validator.NotEmpty;
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.CacheConcurrencyStrategy;
+import org.jboss.blog.tools.validator.Regexp;
+import org.jboss.blog.tools.StringTools;
+import org.jboss.blog.model.post.PostFilter;
+import org.jboss.blog.model.post.filter.CategoryRegexpFilter;
+import org.jboss.blog.model.post.filter.TotalFilter;
+
+import javax.persistence.Entity;
+import javax.persistence.Column;
+import javax.persistence.Transient;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Entity
+ at Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
+public class RemoteFeed extends Feed {
+ @NotEmpty
+ @Length(max = 512)
+ private String remoteLink;
+
+ @Regexp
+ @Column
+ private String includeCategoryRegexp;
+
+ @Transient
+ private PostFilter includeCategoryFilter;
+
+ public String getRemoteLink() {
+ return remoteLink;
+ }
+
+ public void setRemoteLink(String remoteLink) {
+ this.remoteLink = remoteLink;
+ }
+
+ public String getIncludeCategoryRegexp() {
+ return includeCategoryRegexp;
+ }
+
+ public void setIncludeCategoryRegexp(String includeCategoryRegexp) {
+ this.includeCategoryRegexp = includeCategoryRegexp;
+
+ synchronized(this) {
+ includeCategoryFilter = null;
+ }
+ }
+
+ public synchronized PostFilter getIncludeCategoryFilter() {
+ if (includeCategoryFilter == null) {
+ if (StringTools.isEmpty(includeCategoryRegexp)) {
+ includeCategoryFilter = new TotalFilter();
+ } else {
+ includeCategoryFilter = new CategoryRegexpFilter(includeCategoryRegexp);
+ }
+ }
+
+ return includeCategoryFilter;
+ }
+}
Added: feeds100P26/src/model/org/jboss/blog/model/feed/RestrictedFeed.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/feed/RestrictedFeed.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/feed/RestrictedFeed.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,32 @@
+package org.jboss.blog.model.feed;
+
+import java.io.Serializable;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public interface RestrictedFeed extends Serializable {
+ Integer getId();
+
+ String getName();
+
+ String getTitle();
+
+ String getAuthor();
+
+ String getLink();
+
+ String getDescription();
+
+ int getMaxPostsInFeed();
+
+ int getMaxPostsOnPage();
+
+ Boolean getShowDigg();
+
+ Boolean getShowDzone();
+
+ Boolean getShowDelicious();
+
+ boolean isFeedRestricted();
+}
Added: feeds100P26/src/model/org/jboss/blog/model/log/PropositionsLog.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/log/PropositionsLog.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/log/PropositionsLog.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,95 @@
+package org.jboss.blog.model.log;
+
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.security.SecurityUser;
+import org.hibernate.validator.NotNull;
+
+import javax.persistence.*;
+import java.util.Date;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Entity
+ at Table(uniqueConstraints = @UniqueConstraint(columnNames = "feed_id"))
+public class PropositionsLog {
+ @Id
+ @GeneratedValue
+ @Column(updatable = false)
+ private Integer id;
+
+ @NotNull
+ @ManyToOne
+ private Feed feed;
+
+ @NotNull
+ @ManyToOne
+ private SecurityUser securityUser;
+
+ @NotNull
+ @Temporal(TemporalType.TIMESTAMP)
+ private Date date;
+
+ public PropositionsLog() { }
+
+ public PropositionsLog(Feed feed, SecurityUser securityUser, Date date) {
+ this.feed = feed;
+ this.securityUser = securityUser;
+ this.date = date;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public Feed getFeed() {
+ return feed;
+ }
+
+ public void setFeed(Feed feed) {
+ this.feed = feed;
+ }
+
+ public SecurityUser getSecurityUser() {
+ return securityUser;
+ }
+
+ public void setSecurityUser(SecurityUser securityUser) {
+ this.securityUser = securityUser;
+ }
+
+ public Date getDate() {
+ return date;
+ }
+
+ public void setDate(Date date) {
+ this.date = date;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof PropositionsLog)) return false;
+
+ PropositionsLog that = (PropositionsLog) o;
+
+ if (date != null ? !date.equals(that.date) : that.date != null) return false;
+ if (feed != null ? !feed.equals(that.feed) : that.feed != null) return false;
+ if (id != null ? !id.equals(that.id) : that.id != null) return false;
+ if (securityUser != null ? !securityUser.equals(that.securityUser) : that.securityUser != null) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ int result;
+ result = (id != null ? id.hashCode() : 0);
+ result = 31 * result + (feed != null ? feed.hashCode() : 0);
+ result = 31 * result + (securityUser != null ? securityUser.hashCode() : 0);
+ result = 31 * result + (date != null ? date.hashCode() : 0);
+ return result;
+ }
+}
Added: feeds100P26/src/model/org/jboss/blog/model/post/PostFilter.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/post/PostFilter.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/post/PostFilter.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,12 @@
+package org.jboss.blog.model.post;
+
+import org.jboss.blog.model.RestrictedPost;
+
+import java.io.Serializable;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public interface PostFilter extends Serializable {
+ public boolean filter(RestrictedPost post);
+}
Added: feeds100P26/src/model/org/jboss/blog/model/post/filter/AbstractRegexpFilter.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/post/filter/AbstractRegexpFilter.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/post/filter/AbstractRegexpFilter.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,48 @@
+package org.jboss.blog.model.post.filter;
+
+import org.jboss.blog.model.post.PostFilter;
+import org.jboss.blog.tools.validator.Regexp;
+
+import java.util.regex.Pattern;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public abstract class AbstractRegexpFilter implements PostFilter {
+ @Regexp
+ protected String regexp;
+
+ protected transient Pattern pattern;
+
+ protected AbstractRegexpFilter() {
+ }
+
+ protected AbstractRegexpFilter(String regexp) {
+ setRegexp(regexp);
+ }
+
+ public String getRegexp() {
+ return regexp;
+ }
+
+ public void setRegexp(String regexp) {
+ this.regexp = regexp;
+
+ pattern = Pattern.compile(this.regexp);
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof CategoryRegexpFilter)) return false;
+
+ AbstractRegexpFilter that = (AbstractRegexpFilter) o;
+
+ if (regexp != null ? !regexp.equals(that.regexp) : that.regexp != null) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ return (regexp != null ? regexp.hashCode() : 0);
+ }
+}
Added: feeds100P26/src/model/org/jboss/blog/model/post/filter/AndFilter.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/post/filter/AndFilter.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/post/filter/AndFilter.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,71 @@
+package org.jboss.blog.model.post.filter;
+
+import org.jboss.blog.model.RestrictedPost;
+import org.jboss.blog.model.post.PostFilter;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class AndFilter implements PostFilter {
+ private static final long serialVersionUID = 6716831026867502343L;
+
+ private List<PostFilter> filters;
+
+ public AndFilter() {
+ filters = new ArrayList<PostFilter>();
+ }
+
+ public AndFilter(List<PostFilter> filters) {
+ this.filters = filters;
+ }
+
+ public List<PostFilter> getFilters() {
+ return filters;
+ }
+
+ public void setFilters(List<PostFilter> filters) {
+ this.filters = filters;
+ }
+
+ public boolean filter(RestrictedPost post) {
+ for (PostFilter filter : filters) {
+ if (!filter.filter(post)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public String toString() {
+ StringBuilder result = new StringBuilder();
+ result.append("And(");
+ for (Iterator<PostFilter> iter = filters.iterator(); iter.hasNext();) {
+ result.append(iter.next().toString());
+ if (iter.hasNext()) {
+ result.append(", ");
+ }
+ }
+
+ return result.append(")").toString();
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof AndFilter)) return false;
+
+ AndFilter andFilter = (AndFilter) o;
+
+ if (filters != null ? !filters.equals(andFilter.filters) : andFilter.filters != null) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ return (filters != null ? filters.hashCode() : 0);
+ }
+}
Added: feeds100P26/src/model/org/jboss/blog/model/post/filter/AuthorRegexpFilter.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/post/filter/AuthorRegexpFilter.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/post/filter/AuthorRegexpFilter.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,32 @@
+package org.jboss.blog.model.post.filter;
+
+import org.jboss.blog.model.RestrictedPost;
+
+import java.io.IOException;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class AuthorRegexpFilter extends AbstractRegexpFilter {
+ private static final long serialVersionUID = 2015864901762113142L;
+
+ public boolean filter(RestrictedPost post) {
+ return pattern.matcher(post.getEffectiveAuthor()).matches();
+ }
+
+ private void writeObject(java.io.ObjectOutputStream out)
+ throws IOException {
+ out.defaultWriteObject();
+ }
+
+ private void readObject(java.io.ObjectInputStream in)
+ throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+
+ setRegexp(getRegexp());
+ }
+
+ public String toString() {
+ return "Author matching regexp: " + regexp;
+ }
+}
Added: feeds100P26/src/model/org/jboss/blog/model/post/filter/CategoryRegexpFilter.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/post/filter/CategoryRegexpFilter.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/post/filter/CategoryRegexpFilter.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,46 @@
+package org.jboss.blog.model.post.filter;
+
+import org.jboss.blog.model.RestrictedPost;
+import org.jboss.blog.model.RestrictedCategory;
+
+import java.io.IOException;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class CategoryRegexpFilter extends AbstractRegexpFilter {
+ private static final long serialVersionUID = 1209854919382113132L;
+
+ public CategoryRegexpFilter() {
+ }
+
+ public CategoryRegexpFilter(String regexp) {
+ super(regexp);
+ }
+
+ public boolean filter(RestrictedPost post) {
+ for (RestrictedCategory cat : post.getCategories()) {
+ if (pattern.matcher(cat.getName()).matches()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private void writeObject(java.io.ObjectOutputStream out)
+ throws IOException {
+ out.defaultWriteObject();
+ }
+
+ private void readObject(java.io.ObjectInputStream in)
+ throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+
+ setRegexp(getRegexp());
+ }
+
+ public String toString() {
+ return "Category matching regexp: " + regexp;
+ }
+}
Added: feeds100P26/src/model/org/jboss/blog/model/post/filter/NotPodcastFilter.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/post/filter/NotPodcastFilter.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/post/filter/NotPodcastFilter.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,30 @@
+package org.jboss.blog.model.post.filter;
+
+import org.jboss.blog.model.RestrictedPost;
+import org.jboss.blog.model.post.PostFilter;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class NotPodcastFilter implements PostFilter {
+ private static final long serialVersionUID = 3962316121420952911L;
+
+ public boolean filter(RestrictedPost post) {
+ return post.getEnclosures() == null || post.getEnclosures().size() == 0;
+ }
+
+ public String toString() {
+ return "No enclosure (not a podcast entry)";
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof NotPodcastFilter)) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ return NotPodcastFilter.class.hashCode();
+ }
+}
Added: feeds100P26/src/model/org/jboss/blog/model/post/filter/PodcastFilter.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/post/filter/PodcastFilter.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/post/filter/PodcastFilter.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,30 @@
+package org.jboss.blog.model.post.filter;
+
+import org.jboss.blog.model.RestrictedPost;
+import org.jboss.blog.model.post.PostFilter;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class PodcastFilter implements PostFilter {
+ private static final long serialVersionUID = -1115632975507749056L;
+
+ public boolean filter(RestrictedPost post) {
+ return post.getEnclosures() != null && post.getEnclosures().size() != 0;
+ }
+
+ public String toString() {
+ return "With enclosure (a podcast entry)";
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof PodcastFilter)) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ return PodcastFilter.class.hashCode();
+ }
+}
Added: feeds100P26/src/model/org/jboss/blog/model/post/filter/TotalFilter.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/post/filter/TotalFilter.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/post/filter/TotalFilter.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,30 @@
+package org.jboss.blog.model.post.filter;
+
+import org.jboss.blog.model.RestrictedPost;
+import org.jboss.blog.model.post.PostFilter;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class TotalFilter implements PostFilter {
+ private static final long serialVersionUID = -8839681871861904116L;
+
+ public boolean filter(RestrictedPost post) {
+ return true;
+ }
+
+ public String toString() {
+ return "Everything";
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof TotalFilter)) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ return TotalFilter.class.hashCode();
+ }
+}
Added: feeds100P26/src/model/org/jboss/blog/model/security/FeedsSecurityRole.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/security/FeedsSecurityRole.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/security/FeedsSecurityRole.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,11 @@
+package org.jboss.blog.model.security;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public enum FeedsSecurityRole {
+ ADMIN,
+ GROUP_ADMIN,
+ FEED_ADMIN,
+ VIEW
+}
Added: feeds100P26/src/model/org/jboss/blog/model/security/RestrictedSecurityGroup.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/security/RestrictedSecurityGroup.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/security/RestrictedSecurityGroup.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,14 @@
+package org.jboss.blog.model.security;
+
+import java.io.Serializable;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public interface RestrictedSecurityGroup extends Serializable {
+ String getExternalId();
+
+ Object getRealGroup();
+
+ void setRealGroup(Object realGroup);
+}
Added: feeds100P26/src/model/org/jboss/blog/model/security/RestrictedSecurityUser.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/security/RestrictedSecurityUser.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/security/RestrictedSecurityUser.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,12 @@
+package org.jboss.blog.model.security;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public interface RestrictedSecurityUser {
+ String getExternalId();
+
+ Object getRealUser();
+
+ void setRealUser(Object realUser);
+}
Added: feeds100P26/src/model/org/jboss/blog/model/security/SecurityGroup.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/security/SecurityGroup.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/security/SecurityGroup.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,82 @@
+package org.jboss.blog.model.security;
+
+import javax.persistence.*;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Entity
+public class SecurityGroup implements RestrictedSecurityGroup {
+ @Id
+ @GeneratedValue
+ @Column(updatable = false)
+ private Integer id;
+
+ @Column(unique = true)
+ private String externalId;
+
+ @ManyToMany(mappedBy = "groups")
+ private List<SecurityMapping> mappings;
+
+ @Transient
+ private Object realGroup;
+
+ public SecurityGroup() { }
+
+ public SecurityGroup(Object realGroup, String externalId) {
+ this.realGroup = realGroup;
+ this.externalId = externalId;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getExternalId() {
+ return externalId;
+ }
+
+ public void setExternalId(String externalId) {
+ this.externalId = externalId;
+ }
+
+ public List<SecurityMapping> getMappings() {
+ return mappings;
+ }
+
+ public void setMappings(List<SecurityMapping> mappings) {
+ this.mappings = mappings;
+ }
+
+ public Object getRealGroup() {
+ return realGroup;
+ }
+
+ public void setRealGroup(Object realGroup) {
+ this.realGroup = realGroup;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof SecurityGroup)) return false;
+
+ SecurityGroup that = (SecurityGroup) o;
+
+ if (externalId != null ? !externalId.equals(that.externalId) : that.externalId != null) return false;
+ if (id != null ? !id.equals(that.id) : that.id != null) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ int result;
+ result = (id != null ? id.hashCode() : 0);
+ result = 31 * result + (externalId != null ? externalId.hashCode() : 0);
+ return result;
+ }
+}
Added: feeds100P26/src/model/org/jboss/blog/model/security/SecurityMapping.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/security/SecurityMapping.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/security/SecurityMapping.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,92 @@
+package org.jboss.blog.model.security;
+
+import org.hibernate.validator.NotNull;
+
+import javax.persistence.*;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Entity
+ at Table(uniqueConstraints = @UniqueConstraint(columnNames = {"role", "idForRole"}))
+public class SecurityMapping {
+ @Id
+ @GeneratedValue
+ @Column(updatable = false)
+ private Integer id;
+
+ @Column
+ @NotNull
+ private FeedsSecurityRole role;
+
+ @Column
+ private Integer idForRole;
+
+ @ManyToMany
+ private List<SecurityGroup> groups;
+
+ @ManyToMany
+ private List<SecurityUser> users;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public FeedsSecurityRole getRole() {
+ return role;
+ }
+
+ public void setRole(FeedsSecurityRole role) {
+ this.role = role;
+ }
+
+ public Integer getIdForRole() {
+ return idForRole;
+ }
+
+ public void setIdForRole(Integer idForRole) {
+ this.idForRole = idForRole;
+ }
+
+ public List<SecurityGroup> getGroups() {
+ return groups;
+ }
+
+ public void setGroups(List<SecurityGroup> groups) {
+ this.groups = groups;
+ }
+
+ public List<SecurityUser> getUsers() {
+ return users;
+ }
+
+ public void setUsers(List<SecurityUser> users) {
+ this.users = users;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof SecurityMapping)) return false;
+
+ SecurityMapping that = (SecurityMapping) o;
+
+ if (id != null ? !id.equals(that.id) : that.id != null) return false;
+ if (idForRole != null ? !idForRole.equals(that.idForRole) : that.idForRole != null) return false;
+ if (role != that.role) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ int result;
+ result = (id != null ? id.hashCode() : 0);
+ result = 31 * result + (role != null ? role.hashCode() : 0);
+ result = 31 * result + (idForRole != null ? idForRole.hashCode() : 0);
+ return result;
+ }
+}
Added: feeds100P26/src/model/org/jboss/blog/model/security/SecurityUser.java
===================================================================
--- feeds100P26/src/model/org/jboss/blog/model/security/SecurityUser.java (rev 0)
+++ feeds100P26/src/model/org/jboss/blog/model/security/SecurityUser.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,94 @@
+package org.jboss.blog.model.security;
+
+import org.hibernate.validator.NotNull;
+
+import javax.persistence.*;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Entity
+public class SecurityUser implements RestrictedSecurityUser {
+ @Id
+ @GeneratedValue
+ @Column(updatable = false)
+ private Integer id;
+
+ @NotNull
+ private String externalId;
+
+ private String restrictedKey;
+
+ @ManyToMany(mappedBy = "users")
+ private List<SecurityMapping> mappings;
+
+ @Transient
+ private Object realUser;
+
+ public SecurityUser() { }
+
+ public SecurityUser(Object realUser, String externalId) {
+ this.externalId = externalId;
+ this.realUser = realUser;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getExternalId() {
+ return externalId;
+ }
+
+ public void setExternalId(String externalId) {
+ this.externalId = externalId;
+ }
+
+ public Object getRealUser() {
+ return realUser;
+ }
+
+ public void setRealUser(Object realUser) {
+ this.realUser = realUser;
+ }
+
+ public List<SecurityMapping> getMappings() {
+ return mappings;
+ }
+
+ public void setMappings(List<SecurityMapping> mappings) {
+ this.mappings = mappings;
+ }
+
+ public String getRestrictedKey() {
+ return restrictedKey;
+ }
+
+ public void setRestrictedKey(String restrictedKey) {
+ this.restrictedKey = restrictedKey;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof SecurityUser)) return false;
+
+ SecurityUser user = (SecurityUser) o;
+
+ if (externalId != null ? !externalId.equals(user.externalId) : user.externalId != null) return false;
+ if (id != null ? !id.equals(user.id) : user.id != null) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ int result;
+ result = (id != null ? id.hashCode() : 0);
+ result = 31 * result + (externalId != null ? externalId.hashCode() : 0);
+ return result;
+ }
+}
Added: feeds100P26/src/portal/org/jboss/blog/portlet/BlogPortlet.java
===================================================================
--- feeds100P26/src/portal/org/jboss/blog/portlet/BlogPortlet.java (rev 0)
+++ feeds100P26/src/portal/org/jboss/blog/portlet/BlogPortlet.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,78 @@
+package org.jboss.blog.portlet;
+
+import org.jboss.blog.service.FeedsService;
+import org.jboss.blog.service.LinkService;
+import org.jboss.blog.service.FeedNotFoundException;
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.RestrictedPost;
+import org.jboss.seam.Component;
+import org.jboss.seam.contexts.Contexts;
+import org.jboss.seam.contexts.Lifecycle;
+
+import javax.portlet.*;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class BlogPortlet extends GenericPortlet {
+ protected void doView(RenderRequest request, RenderResponse response)
+ throws PortletException, IOException {
+ boolean createContexts = !Contexts.isEventContextActive() && !Contexts.isApplicationContextActive();
+ if (createContexts) {
+ Lifecycle.beginCall();
+ }
+
+ try {
+ // Getting the services
+ FeedsService feedsService = (FeedsService) Component.getInstance("feedsService");
+ LinkService linkService = (LinkService) Component.getInstance("linkService");
+
+ // Reading the preferences
+ PortletPreferences preferences = request.getPreferences();
+ String feedName = preferences.getValue("feedName", null);
+
+ String numberOfPostsPerPageString = preferences.getValue("numberOfPosts", "5");
+ int numberOfPostsPerPage = Integer.parseInt(numberOfPostsPerPageString);
+
+ String summaryLengthString = preferences.getValue("summaryLength", "200");
+ Integer summaryLength = Integer.valueOf(summaryLengthString);
+
+ String showDateString = preferences.getValue("showDate", "true");
+ Boolean showDate = Boolean.valueOf(showDateString);
+
+ String jsp = preferences.getValue("jsp", "/view.jsp");
+
+ response.setContentType("text/html");
+
+ try {
+ Feed feed = feedsService.getFeed(feedName);
+
+ // Reading posts
+ List<? extends RestrictedPost> posts = feedsService.getPosts(feed, 0, numberOfPostsPerPage);
+
+ // Setting request attributes
+ request.setAttribute("feed", feed);
+ request.setAttribute("posts", posts);
+ request.setAttribute("summaryLength", summaryLength);
+ request.setAttribute("showDate", showDate);
+ request.setAttribute("linkService", linkService);
+
+ response.setTitle(feed.getTitle());
+ // Including the jsp
+ PortletRequestDispatcher rd = getPortletContext().getRequestDispatcher(jsp);
+ rd.include(request, response);
+ } catch (FeedNotFoundException e) {
+ request.setAttribute("feedName", feedName);
+
+ PortletRequestDispatcher rd = getPortletContext().getRequestDispatcher("/feed_not_found.jsp");
+ rd.include(request, response);
+ }
+ } finally {
+ if (createContexts) {
+ Lifecycle.endCall();
+ }
+ }
+ }
+}
Added: feeds100P26/src/portal/org/jboss/blog/session/security/external/PortalExternalSecurityService.java
===================================================================
--- feeds100P26/src/portal/org/jboss/blog/session/security/external/PortalExternalSecurityService.java (rev 0)
+++ feeds100P26/src/portal/org/jboss/blog/session/security/external/PortalExternalSecurityService.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,186 @@
+package org.jboss.blog.session.security.external;
+
+import org.jboss.seam.annotations.*;
+import org.jboss.seam.log.Log;
+import org.jboss.seam.ScopeType;
+import org.jboss.blog.model.security.SecurityUser;
+import org.jboss.blog.model.security.SecurityGroup;
+import org.jboss.blog.model.security.RestrictedSecurityGroup;
+import org.jboss.blog.model.security.RestrictedSecurityUser;
+import org.jboss.blog.session.security.InvalidLoginException;
+
+import javax.persistence.EntityManager;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("externalSecurityService")
+ at AutoCreate
+ at Scope(ScopeType.STATELESS)
+public class PortalExternalSecurityService extends AbstractExternalSecurityService {
+ @In
+ private EntityManager entityManager;
+
+ @In
+ private PortalSecurityService portalSecurityService;
+
+ protected EntityManager getEntityManager() {
+ return entityManager;
+ }
+
+ @Logger
+ private Log log;
+
+ private List<SecurityGroup> convertRoles(List<PortalRole> roles, boolean getUnrestricted) {
+ List<SecurityGroup> securityGroups = new ArrayList<SecurityGroup>();
+
+ for (PortalRole role : roles) {
+ SecurityGroup securityGroup = new SecurityGroup(role, role.getId());
+ if (getUnrestricted) {
+ securityGroups.add(getUnrestrictedSecurityGroup(securityGroup));
+ } else {
+ securityGroups.add(securityGroup);
+ }
+ }
+
+ return securityGroups;
+ }
+
+ private List<SecurityUser> convertUsers(List<PortalUser> users, boolean getUnrestricted) {
+ List<SecurityUser> securityUsers = new ArrayList<SecurityUser>();
+
+ for (PortalUser user : users) {
+ SecurityUser securityUser = new SecurityUser(user, user.getId());
+ if (getUnrestricted) {
+ securityUsers.add(getUnrestrictedSecurityUser(securityUser));
+ } else {
+ securityUsers.add(securityUser);
+ }
+ }
+
+ return securityUsers;
+ }
+
+ private PortalRole getRealRole(RestrictedSecurityGroup securityGroup) throws PortalSecurityException {
+ if (securityGroup.getRealGroup() == null) {
+ PortalRole role = portalSecurityService.getRoleById(securityGroup.getExternalId());
+ securityGroup.setRealGroup(role);
+
+ return role;
+ } else {
+ return (PortalRole) securityGroup.getRealGroup();
+ }
+ }
+
+ private PortalUser getRealUser(RestrictedSecurityUser securityUser) throws PortalSecurityException {
+ if (securityUser.getRealUser() == null) {
+ PortalUser user = portalSecurityService.getUserById(securityUser.getExternalId());
+ securityUser.setRealUser(user);
+
+ return user;
+ } else {
+ return (PortalUser) securityUser.getRealUser();
+ }
+ }
+
+ public SecurityUser authenticate(String username, String password) throws InvalidLoginException {
+ try {
+ PortalUser portalUser = portalSecurityService.authenticate(username, password);
+
+ SecurityUser securityUser = new SecurityUser();
+ securityUser.setExternalId(portalUser.getId());
+ securityUser.setRealUser(portalUser);
+
+ return getUnrestrictedSecurityUser(securityUser);
+ } catch (PortalSecurityException e) {
+ log.error(e);
+ throw new InvalidLoginException();
+ }
+ }
+
+ public List<? extends RestrictedSecurityGroup> getAllGroups() {
+ try {
+ //noinspection unchecked
+ return convertRoles(portalSecurityService.getAllRoles(), false);
+ } catch (PortalSecurityException e) {
+ log.error(e);
+ return new ArrayList<RestrictedSecurityGroup>();
+ }
+ }
+
+ public List<? extends RestrictedSecurityUser> getUsers(int start, int count) {
+ try {
+ //noinspection unchecked
+ return convertUsers(portalSecurityService.getUsers(start, count), false);
+ } catch (PortalSecurityException e) {
+ log.error(e);
+ return new ArrayList<RestrictedSecurityUser>();
+ }
+ }
+
+ public List<? extends RestrictedSecurityUser> getUsers(String filter, int start, int count) {
+ try {
+ //noinspection unchecked
+ return convertUsers(portalSecurityService.getUsers(filter, start, count), false);
+ } catch (PortalSecurityException e) {
+ log.error(e);
+ return new ArrayList<RestrictedSecurityUser>();
+ }
+ }
+
+ public List<SecurityGroup> getGroupsOfUser(SecurityUser securityUser) {
+ try {
+ //noinspection unchecked
+ return convertRoles(portalSecurityService.getRolesOfUser(securityUser.getExternalId()), true);
+ } catch (PortalSecurityException e) {
+ log.error(e);
+ return new ArrayList<SecurityGroup>();
+ }
+ }
+
+ public List<? extends RestrictedSecurityUser> getUsersInGroup(RestrictedSecurityGroup securityGroup) {
+ try {
+ return convertUsers(portalSecurityService.getUsersInRole(securityGroup.getExternalId()), false);
+ } catch (PortalSecurityException e) {
+ log.error(e);
+ return new ArrayList<RestrictedSecurityUser>();
+ }
+ }
+
+ public String getEmail(RestrictedSecurityUser securityUser) {
+ try {
+ return getRealUser(securityUser).getEmail();
+ } catch (PortalSecurityException e) {
+ log.error(e);
+ return null;
+ }
+ }
+
+ public String getDisplayName(RestrictedSecurityUser securityUser) {
+ try {
+ return getRealUser(securityUser).getDisplayName();
+ } catch (PortalSecurityException e) {
+ return "<? " + e.getMessage() + ">";
+ }
+ }
+
+ public String getDisplayName(RestrictedSecurityGroup securityGroup) {
+ try {
+ return getRealRole(securityGroup).getDisplayName();
+ } catch (PortalSecurityException e) {
+ return "<? " + e.getMessage() + ">";
+ }
+ }
+
+ public RestrictedSecurityGroup getAdminGroup() {
+ try {
+ PortalRole portalRole = portalSecurityService.getAdminRole();
+
+ return new SecurityGroup(portalRole, portalRole.getId());
+ } catch (PortalSecurityException e) {
+ return null;
+ }
+ }
+}
\ No newline at end of file
Added: feeds100P26/src/portal/org/jboss/blog/session/security/external/PortalRole.java
===================================================================
--- feeds100P26/src/portal/org/jboss/blog/session/security/external/PortalRole.java (rev 0)
+++ feeds100P26/src/portal/org/jboss/blog/session/security/external/PortalRole.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,22 @@
+package org.jboss.blog.session.security.external;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class PortalRole {
+ private String id;
+ private String displayName;
+
+ public PortalRole(String id, String displayName) {
+ this.id = id;
+ this.displayName = displayName;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+}
Added: feeds100P26/src/portal/org/jboss/blog/session/security/external/PortalSecurityException.java
===================================================================
--- feeds100P26/src/portal/org/jboss/blog/session/security/external/PortalSecurityException.java (rev 0)
+++ feeds100P26/src/portal/org/jboss/blog/session/security/external/PortalSecurityException.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,23 @@
+package org.jboss.blog.session.security.external;
+
+import javax.naming.NamingException;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class PortalSecurityException extends Exception {
+ public PortalSecurityException() {
+ }
+
+ public PortalSecurityException(String message) {
+ super(message);
+ }
+
+ public PortalSecurityException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public PortalSecurityException(Throwable cause) {
+ super(cause);
+ }
+}
Added: feeds100P26/src/portal/org/jboss/blog/session/security/external/PortalSecurityService.java
===================================================================
--- feeds100P26/src/portal/org/jboss/blog/session/security/external/PortalSecurityService.java (rev 0)
+++ feeds100P26/src/portal/org/jboss/blog/session/security/external/PortalSecurityService.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,32 @@
+package org.jboss.blog.session.security.external;
+
+import org.jboss.blog.session.security.InvalidLoginException;
+
+import javax.ejb.Local;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Local
+public interface PortalSecurityService {
+ PortalUser authenticate(String username, String password) throws PortalSecurityException, InvalidLoginException;
+
+ List<PortalRole> getAllRoles() throws PortalSecurityException;
+
+ public List<PortalUser> getUsers(int start, int count) throws PortalSecurityException;
+
+ public List<PortalUser> getUsers(String filter, int start, int count) throws PortalSecurityException;
+
+ List<PortalRole> getRolesOfUser(String id) throws PortalSecurityException;
+
+ List<PortalUser> getUsersInRole(String id) throws PortalSecurityException;
+
+ PortalRole getAdminRole() throws PortalSecurityException;
+
+ PortalRole getRoleById(String id) throws PortalSecurityException;
+
+ PortalUser getUserById(String id) throws PortalSecurityException;
+
+ void remove();
+}
Added: feeds100P26/src/portal/org/jboss/blog/session/security/external/PortalSecurityServiceImpl.java
===================================================================
--- feeds100P26/src/portal/org/jboss/blog/session/security/external/PortalSecurityServiceImpl.java (rev 0)
+++ feeds100P26/src/portal/org/jboss/blog/session/security/external/PortalSecurityServiceImpl.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,218 @@
+package org.jboss.blog.session.security.external;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ejb.Remove;
+import javax.ejb.Stateless;
+import javax.ejb.TransactionAttribute;
+import javax.ejb.TransactionAttributeType;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
+import org.jboss.blog.session.security.InvalidLoginException;
+import org.jboss.blog.tools.StringTools;
+import org.jboss.portal.identity.IdentityException;
+import org.jboss.portal.identity.MembershipModule;
+import org.jboss.portal.identity.NoSuchUserException;
+import org.jboss.portal.identity.Role;
+import org.jboss.portal.identity.RoleModule;
+import org.jboss.portal.identity.User;
+import org.jboss.portal.identity.UserModule;
+import org.jboss.portal.identity.UserProfileModule;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.annotations.Logger;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.log.Log;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Stateless
+ at Name("portalSecurityService")
+ at AutoCreate
+public class PortalSecurityServiceImpl implements PortalSecurityService {
+ @Logger
+ private Log log;
+
+ private UserModule getUserModule() throws PortalSecurityException {
+ try {
+ return (UserModule) new InitialContext().lookup("java:portal/UserModule");
+ } catch (NamingException e) {
+ log.error(e);
+ throw new PortalSecurityException(e);
+ }
+ }
+
+ private RoleModule getRoleModule() throws PortalSecurityException {
+ try {
+ return (RoleModule) new InitialContext().lookup("java:portal/RoleModule");
+ } catch (NamingException e) {
+ log.error(e);
+ throw new PortalSecurityException(e);
+ }
+ }
+
+ private MembershipModule getMembershipModule() throws PortalSecurityException {
+ try {
+ return (MembershipModule) new InitialContext().lookup("java:portal/MembershipModule");
+ } catch (NamingException e) {
+ log.error(e);
+ throw new PortalSecurityException(e);
+ }
+ }
+
+ private UserProfileModule getProfileModule() throws PortalSecurityException {
+ try {
+ return (UserProfileModule) new InitialContext().lookup("java:portal/UserProfileModule");
+ } catch (NamingException e) {
+ log.error(e);
+ throw new PortalSecurityException(e);
+ }
+ }
+
+ private String getUserEmail(User user) throws PortalSecurityException {
+ try {
+ return StringTools.safeToString(getProfileModule().getProperty(user, User.INFO_USER_EMAIL_REAL));
+ } catch (IdentityException e) {
+ throw new PortalSecurityException(e);
+ }
+ }
+
+ @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
+ public PortalUser authenticate(String username, String password)
+ throws InvalidLoginException, PortalSecurityException {
+ User user;
+ try {
+ user = getUserModule().findUserByUserName(username);
+ } catch (NoSuchUserException e) {
+ throw new InvalidLoginException();
+ } catch (IdentityException e) {
+ throw new PortalSecurityException(e);
+ }
+
+ if (!user.validatePassword(password)) {
+ throw new InvalidLoginException();
+ }
+
+ return new PortalUser(user.getId().toString(), user.getUserName(), getUserEmail(user));
+ }
+
+ @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
+ public List<PortalRole> getAllRoles() throws PortalSecurityException {
+ try {
+ List<PortalRole> roles = new ArrayList<PortalRole>();
+
+ for (Object roleObj : getRoleModule().findRoles()) {
+ Role role = (Role) roleObj;
+ roles.add(new PortalRole(role.getId().toString(), role.getDisplayName()));
+ }
+
+ return roles;
+ } catch (IdentityException e) {
+ throw new PortalSecurityException(e);
+ }
+ }
+
+ @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
+ public List<PortalUser> getUsers(int start, int count) throws PortalSecurityException {
+ try {
+ List<PortalUser> users = new ArrayList<PortalUser>();
+
+ for (Object userObj : getUserModule().findUsers(start, count)) {
+ User user = (User) userObj;
+ users.add(new PortalUser(user.getId().toString(), user.getUserName(), getUserEmail(user)));
+ }
+
+ return users;
+ } catch (IdentityException e) {
+ throw new PortalSecurityException(e);
+ }
+ }
+
+ @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
+ public List<PortalUser> getUsers(String filter, int start, int count) throws PortalSecurityException {
+ try {
+ List<PortalUser> users = new ArrayList<PortalUser>();
+
+ for (Object userObj : getUserModule().findUsersFilteredByUserName(filter, start, count)) {
+ User user = (User) userObj;
+ users.add(new PortalUser(user.getId().toString(), user.getUserName(), getUserEmail(user)));
+ }
+
+ return users;
+ } catch (IdentityException e) {
+ throw new PortalSecurityException(e);
+ }
+ }
+
+ @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
+ public List<PortalRole> getRolesOfUser(String id) throws PortalSecurityException {
+ try {
+ List<PortalRole> roles = new ArrayList<PortalRole>();
+
+ for (Object roleObj : getMembershipModule().getRoles(getUserModule().findUserById(id))) {
+ Role role = (Role) roleObj;
+ roles.add(new PortalRole(role.getId().toString(), role.getDisplayName()));
+ }
+
+ return roles;
+ } catch (IdentityException e) {
+ throw new PortalSecurityException(e);
+ }
+ }
+
+ @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
+ public List<PortalUser> getUsersInRole(String id) throws PortalSecurityException {
+ try {
+ List<PortalUser> users = new ArrayList<PortalUser>();
+
+ for (Object roleObj : getMembershipModule().getUsers(getRoleModule().findRoleById(id))) {
+ User user = (User) roleObj;
+ users.add(new PortalUser(user.getId().toString(), user.getUserName(), getUserEmail(user)));
+ }
+
+ return users;
+ } catch (IdentityException e) {
+ throw new PortalSecurityException(e);
+ }
+ }
+
+ @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
+ public PortalRole getAdminRole() throws PortalSecurityException {
+ try {
+ Role adminRole = getRoleModule().findRoleByName("Admin");
+
+ if (adminRole == null) {
+ return null;
+ }
+
+ return new PortalRole(adminRole.getId().toString(), adminRole.getDisplayName());
+ } catch (IdentityException e) {
+ throw new PortalSecurityException(e);
+ }
+ }
+
+ @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
+ public PortalRole getRoleById(String id) throws PortalSecurityException {
+ try {
+ Role role = getRoleModule().findRoleById(id);
+ return new PortalRole(role.getId().toString(), role.getDisplayName());
+ } catch (IdentityException e) {
+ throw new PortalSecurityException(e);
+ }
+ }
+
+ @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
+ public PortalUser getUserById(String id) throws PortalSecurityException {
+ try {
+ User user = getUserModule().findUserById(id);
+ return new PortalUser(user.getId().toString(), user.getUserName(), getUserEmail(user));
+ } catch (IdentityException e) {
+ throw new PortalSecurityException(e);
+ }
+ }
+
+ @Remove
+ public void remove() { }
+}
Added: feeds100P26/src/portal/org/jboss/blog/session/security/external/PortalUser.java
===================================================================
--- feeds100P26/src/portal/org/jboss/blog/session/security/external/PortalUser.java (rev 0)
+++ feeds100P26/src/portal/org/jboss/blog/session/security/external/PortalUser.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,28 @@
+package org.jboss.blog.session.security.external;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class PortalUser {
+ private String id;
+ private String displayName;
+ private String email;
+
+ public PortalUser(String id, String displayName, String email) {
+ this.id = id;
+ this.displayName = displayName;
+ this.email = email;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+}
Added: feeds100P26/src/portal/org/jboss/blog/session/security/external/SecurityBootstrap.java
===================================================================
--- feeds100P26/src/portal/org/jboss/blog/session/security/external/SecurityBootstrap.java (rev 0)
+++ feeds100P26/src/portal/org/jboss/blog/session/security/external/SecurityBootstrap.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,45 @@
+package org.jboss.blog.session.security.external;
+
+import org.jboss.seam.annotations.*;
+import org.jboss.seam.ScopeType;
+import org.jboss.blog.session.security.SecurityModBean;
+import org.jboss.blog.model.security.SecurityGroup;
+import org.jboss.blog.model.security.FeedsSecurityRole;
+import org.jboss.blog.model.security.RestrictedSecurityGroup;
+
+import javax.persistence.EntityManager;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("securityBootstrap")
+ at Scope(ScopeType.STATELESS)
+public class SecurityBootstrap {
+ @In
+ private SecurityModBean securityMod;
+
+ @In
+ private ExternalSecurityService externalSecurityService;
+
+ @In
+ private EntityManager entityManager;
+
+ @Observer("org.jboss.blog.postBlogInit")
+ @Transactional
+ public void initAdministrator() {
+ List<SecurityGroup> administratorGroups = securityMod.getAdministratorGroups();
+ if (administratorGroups == null || administratorGroups.size() == 0) {
+ RestrictedSecurityGroup group = externalSecurityService.getAdminGroup();
+
+ if (group != null) {
+ securityMod.setRole(FeedsSecurityRole.ADMIN);
+ securityMod.setRestrictedSecurityGroup(group);
+
+ securityMod.addSecurityGroupAsSuperUser();
+
+ entityManager.flush();
+ }
+ }
+ }
+}
Added: feeds100P26/src/services/org/jboss/blog/service/FeedNotFoundException.java
===================================================================
--- feeds100P26/src/services/org/jboss/blog/service/FeedNotFoundException.java (rev 0)
+++ feeds100P26/src/services/org/jboss/blog/service/FeedNotFoundException.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,21 @@
+package org.jboss.blog.service;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class FeedNotFoundException extends Exception {
+ public FeedNotFoundException() {
+ }
+
+ public FeedNotFoundException(String message) {
+ super(message);
+ }
+
+ public FeedNotFoundException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public FeedNotFoundException(Throwable cause) {
+ super(cause);
+ }
+}
Added: feeds100P26/src/services/org/jboss/blog/service/FeedsService.java
===================================================================
--- feeds100P26/src/services/org/jboss/blog/service/FeedsService.java (rev 0)
+++ feeds100P26/src/services/org/jboss/blog/service/FeedsService.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,31 @@
+package org.jboss.blog.service;
+
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.feed.RestrictedFeed;
+import org.jboss.blog.model.Post;
+import org.jboss.blog.model.RestrictedPost;
+
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public interface FeedsService {
+ Post getPost(String titleAsId) throws PostNotFoundException;
+
+ Feed getFeed(String feedName) throws FeedNotFoundException;
+
+ List<? extends RestrictedPost> getPosts(RestrictedFeed feed, int from, int to);
+
+ /**
+ *
+ * @param feed Feed of which posts to get.
+ * @param from Starting post.
+ * @param to Ending post.
+ * @param restricted Should restricted posts be included.
+ * @return A list of posts of the given feed, of length max. to-from.
+ */
+ List<? extends RestrictedPost> getPosts(RestrictedFeed feed, int from, int to, boolean restricted);
+
+ List<? extends RestrictedPost> getPosts(int from, int to);
+}
Added: feeds100P26/src/services/org/jboss/blog/service/GroupsService.java
===================================================================
--- feeds100P26/src/services/org/jboss/blog/service/GroupsService.java (rev 0)
+++ feeds100P26/src/services/org/jboss/blog/service/GroupsService.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,21 @@
+package org.jboss.blog.service;
+
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.Group;
+
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public interface GroupsService {
+ List<Group> getAllGroups();
+
+ List<Feed> acceptedFeeds(Group group);
+
+ List<Feed> unacceptedFeeds(Group group);
+
+ List<Feed> restrictedFeeds(Group group);
+
+ List<Feed> allAcceptedFeeds(Group group);
+}
Added: feeds100P26/src/services/org/jboss/blog/service/LinkService.java
===================================================================
--- feeds100P26/src/services/org/jboss/blog/service/LinkService.java (rev 0)
+++ feeds100P26/src/services/org/jboss/blog/service/LinkService.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,24 @@
+package org.jboss.blog.service;
+
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.XmlType;
+import org.jboss.blog.model.Post;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public interface LinkService {
+ String getServerAddress();
+
+ void setServerAddress(String serverAddress);
+
+ String getContextName();
+
+ void setContextName(String contextName);
+
+ String generateFeedLink(Feed feed, XmlType type);
+
+ String generateFeedPageLink(Feed feed);
+
+ String generatePostLink(Post post);
+}
Added: feeds100P26/src/services/org/jboss/blog/service/PostNotFoundException.java
===================================================================
--- feeds100P26/src/services/org/jboss/blog/service/PostNotFoundException.java (rev 0)
+++ feeds100P26/src/services/org/jboss/blog/service/PostNotFoundException.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,21 @@
+package org.jboss.blog.service;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class PostNotFoundException extends Exception {
+ public PostNotFoundException() {
+ }
+
+ public PostNotFoundException(String message) {
+ super(message);
+ }
+
+ public PostNotFoundException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public PostNotFoundException(Throwable cause) {
+ super(cause);
+ }
+}
Added: feeds100P26/src/shotoku/org/jboss/blog/model/shotoku/ShotokuFeed.java
===================================================================
--- feeds100P26/src/shotoku/org/jboss/blog/model/shotoku/ShotokuFeed.java (rev 0)
+++ feeds100P26/src/shotoku/org/jboss/blog/model/shotoku/ShotokuFeed.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,51 @@
+package org.jboss.blog.model.shotoku;
+
+import org.jboss.blog.model.feed.Feed;
+import org.hibernate.validator.NotNull;
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.CacheConcurrencyStrategy;
+
+import javax.persistence.Entity;
+import javax.persistence.Column;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Entity
+ at Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
+public class ShotokuFeed extends Feed {
+ @NotNull
+ @Column
+ private String cmId;
+
+ @NotNull
+ @Column
+ private String cmPath;
+
+ @Column
+ private String podcastPrefix;
+
+ public String getCmId() {
+ return cmId;
+ }
+
+ public void setCmId(String cmId) {
+ this.cmId = cmId;
+ }
+
+ public String getCmPath() {
+ return cmPath;
+ }
+
+ public void setCmPath(String cmPath) {
+ this.cmPath = cmPath;
+ }
+
+ public String getPodcastPrefix() {
+ return podcastPrefix;
+ }
+
+ public void setPodcastPrefix(String podcastPrefix) {
+ this.podcastPrefix = podcastPrefix;
+ }
+}
Added: feeds100P26/src/shotoku/org/jboss/blog/session/feed/dao/ShotokuFeedDao.java
===================================================================
--- feeds100P26/src/shotoku/org/jboss/blog/session/feed/dao/ShotokuFeedDao.java (rev 0)
+++ feeds100P26/src/shotoku/org/jboss/blog/session/feed/dao/ShotokuFeedDao.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,36 @@
+package org.jboss.blog.session.feed.dao;
+
+import org.jboss.blog.model.RestrictedPost;
+import org.jboss.blog.model.shotoku.ShotokuFeed;
+import org.jboss.blog.session.feed.posts.DatabaseFeedPosts;
+import org.jboss.blog.session.feed.type.FeedType;
+import org.jboss.blog.session.feed.update.ShotokuFeedUpdate;
+import org.jboss.blog.session.update.UpdateException;
+import org.jboss.seam.Component;
+
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at FeedType(
+ name = "shotoku",
+ addPage = "/manage/shotoku/shotoku_add.xhtml",
+ editPage = "/manage/shotoku/shotoku_edit.xhtml",
+ model = ShotokuFeed.class)
+public class ShotokuFeedDao implements FeedDao {
+ private ShotokuFeed shotokuFeed;
+
+ public ShotokuFeedDao(ShotokuFeed shotokuFeed) {
+ this.shotokuFeed = shotokuFeed;
+ }
+
+ public List<? extends RestrictedPost> getPosts(int from, int to, boolean restricted) {
+ return ((DatabaseFeedPosts) Component.getInstance("databaseFeedPosts")).getPosts(
+ shotokuFeed, from, to);
+ }
+
+ public void update() throws UpdateException {
+ ((ShotokuFeedUpdate) Component.getInstance("shotokuFeedUpdate")).update(shotokuFeed);
+ }
+}
Added: feeds100P26/src/shotoku/org/jboss/blog/session/feed/mod/ShotokuModBean.java
===================================================================
--- feeds100P26/src/shotoku/org/jboss/blog/session/feed/mod/ShotokuModBean.java (rev 0)
+++ feeds100P26/src/shotoku/org/jboss/blog/session/feed/mod/ShotokuModBean.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,133 @@
+package org.jboss.blog.session.feed.mod;
+
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.security.Restrict;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.faces.FacesMessages;
+import org.jboss.seam.core.Events;
+import org.jboss.blog.model.shotoku.ShotokuFeed;
+import org.jboss.blog.model.Post;
+import org.jboss.blog.session.feed.InvalidFeedTypeException;
+import org.jboss.blog.session.shotoku.ShotokuFeedService;
+import org.jboss.blog.session.shotoku.PostContentTooLargeException;
+import org.jboss.blog.session.shotoku.ShotokuException;
+import org.jboss.shotoku.exceptions.RepositoryException;
+
+import javax.persistence.EntityManager;
+import javax.faces.application.FacesMessage;
+import java.util.List;
+import java.io.Serializable;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Scope(ScopeType.CONVERSATION)
+ at Name("shotokuFeedMod")
+public class ShotokuModBean implements Serializable {
+ @In
+ private FeedModBean feedMod;
+
+ @In
+ private EntityManager entityManager;
+
+ @In
+ private FacesMessages facesMessages;
+
+ @In
+ private PostsValidator postsValidator;
+
+ @In
+ private ShotokuFeedService shotokuFeedService;
+
+ private ShotokuFeed shotokuFeed;
+
+ private Boolean podcast;
+
+ private boolean pathOk;
+ private Exception pathException;
+
+ private List<Post> posts;
+
+ public ShotokuFeed getShotokuFeed() throws InvalidFeedTypeException {
+ if (shotokuFeed == null) {
+ if (feedMod.getFeed() == null) {
+ shotokuFeed = new ShotokuFeed();
+ feedMod.initNewFeed(shotokuFeed);
+
+ shotokuFeed.setCmId("default");
+ } else {
+ if (feedMod.getFeed() instanceof ShotokuFeed) {
+ shotokuFeed = (ShotokuFeed) feedMod.getFeed();
+ } else {
+ throw new InvalidFeedTypeException();
+ }
+ }
+ }
+
+ return shotokuFeed;
+ }
+
+ public boolean isPathOk() {
+ return pathOk;
+ }
+
+ public void setPathOk(boolean pathOk) {
+ this.pathOk = pathOk;
+ }
+
+ public Exception getPathException() {
+ return pathException;
+ }
+
+ public void setPathException(Exception pathException) {
+ this.pathException = pathException;
+ }
+
+ public boolean isPodcast() throws InvalidFeedTypeException {
+ if (podcast == null) {
+ podcast = getShotokuFeed().getPodcastPrefix() != null;
+ }
+
+ return podcast;
+ }
+
+ public void setPodcast(boolean podcast) {
+ this.podcast = podcast;
+ }
+
+ public void checkPath() throws InvalidFeedTypeException {
+ try {
+ posts = shotokuFeedService.getPosts(getShotokuFeed());
+
+ if (!postsValidator.validatePosts(posts, false, "cmPath")) {
+ throw new RepositoryException("Some files are missing required properties.");
+ }
+
+ setPathOk(true);
+ } catch (ShotokuException e) {
+ setPathOk(false);
+ setPathException(e);
+ } catch (PostContentTooLargeException e) {
+ setPathOk(false);
+ setPathException(e);
+ }
+ }
+
+ public void saveNew() throws InvalidFeedTypeException {
+ getShotokuFeed().setPosts(posts);
+ }
+
+ @Restrict("#{identity.hasPermission('feed', 'edit', feedMod.feed, feedMod.feed.group)}")
+ public void saveExisting() throws InvalidFeedTypeException {
+ shotokuFeedService.refreshEnclosureLinks(getShotokuFeed());
+
+ entityManager.flush();
+
+ facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, "blog.feed.updated",
+ getShotokuFeed().getName());
+
+ Events.instance().raiseEvent("org.jboss.blog.feed.updated", getShotokuFeed());
+ }
+}
Added: feeds100P26/src/shotoku/org/jboss/blog/session/feed/update/ShotokuFeedUpdate.java
===================================================================
--- feeds100P26/src/shotoku/org/jboss/blog/session/feed/update/ShotokuFeedUpdate.java (rev 0)
+++ feeds100P26/src/shotoku/org/jboss/blog/session/feed/update/ShotokuFeedUpdate.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,53 @@
+package org.jboss.blog.session.feed.update;
+
+import org.jboss.blog.model.shotoku.ShotokuFeed;
+import org.jboss.blog.model.Post;
+import org.jboss.blog.session.merge.MergeServiceBean;
+import org.jboss.blog.session.update.UpdateException;
+import org.jboss.blog.session.feed.lock.FeedsLocksBean;
+import org.jboss.blog.session.shotoku.ShotokuFeedService;
+import org.jboss.blog.session.shotoku.PostContentTooLargeException;
+import org.jboss.blog.session.shotoku.ShotokuException;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+
+import java.util.concurrent.locks.Lock;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Name("shotokuFeedUpdate")
+ at Scope(ScopeType.STATELESS)
+public class ShotokuFeedUpdate {
+ @In
+ private ShotokuFeedService shotokuFeedService;
+
+ @In
+ private MergeServiceBean mergeService;
+
+ @In
+ private FeedsLocksBean feedsLocks;
+
+ public void update(ShotokuFeed feed) throws UpdateException {
+ Lock feedLock = feedsLocks.getLockForFeed(feed.getName());
+ feedLock.lock();
+ try {
+ List<Post> posts;
+
+ try {
+ posts = shotokuFeedService.getPosts(feed);
+ } catch (ShotokuException e) {
+ throw new UpdateException(e);
+ } catch (PostContentTooLargeException e) {
+ throw new UpdateException(e);
+ }
+
+ mergeService.merge(feed, posts);
+ } finally {
+ feedLock.unlock();
+ }
+ }
+}
Added: feeds100P26/src/shotoku/org/jboss/blog/session/shotoku/PostContentTooLargeException.java
===================================================================
--- feeds100P26/src/shotoku/org/jboss/blog/session/shotoku/PostContentTooLargeException.java (rev 0)
+++ feeds100P26/src/shotoku/org/jboss/blog/session/shotoku/PostContentTooLargeException.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,21 @@
+package org.jboss.blog.session.shotoku;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class PostContentTooLargeException extends Exception {
+ public PostContentTooLargeException() {
+ }
+
+ public PostContentTooLargeException(String message) {
+ super(message);
+ }
+
+ public PostContentTooLargeException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public PostContentTooLargeException(Throwable cause) {
+ super(cause);
+ }
+}
Added: feeds100P26/src/shotoku/org/jboss/blog/session/shotoku/ShotokuException.java
===================================================================
--- feeds100P26/src/shotoku/org/jboss/blog/session/shotoku/ShotokuException.java (rev 0)
+++ feeds100P26/src/shotoku/org/jboss/blog/session/shotoku/ShotokuException.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,23 @@
+package org.jboss.blog.session.shotoku;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class ShotokuException extends Exception {
+ public ShotokuException() {
+ }
+
+ public ShotokuException(String message) {
+ super(message);
+ }
+
+ public ShotokuException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public ShotokuException(Throwable cause) {
+ super(cause);
+ }
+}
+
+
Added: feeds100P26/src/shotoku/org/jboss/blog/session/shotoku/ShotokuFeedService.java
===================================================================
--- feeds100P26/src/shotoku/org/jboss/blog/session/shotoku/ShotokuFeedService.java (rev 0)
+++ feeds100P26/src/shotoku/org/jboss/blog/session/shotoku/ShotokuFeedService.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,108 @@
+package org.jboss.blog.session.shotoku;
+
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.AutoCreate;
+import org.jboss.seam.annotations.In;
+import org.jboss.seam.ScopeType;
+import org.jboss.blog.model.Post;
+import org.jboss.blog.model.Enclosure;
+import org.jboss.blog.model.Image;
+import org.jboss.blog.model.Category;
+import org.jboss.blog.model.shotoku.ShotokuFeed;
+import org.jboss.blog.service.LinkService;
+import org.jboss.blog.tools.StringTools;
+import org.jboss.shotoku.ContentManager;
+import org.jboss.shotoku.Node;
+import org.jboss.shotoku.Directory;
+import org.jboss.shotoku.exceptions.RepositoryException;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at Scope(ScopeType.STATELESS)
+ at Name("shotokuFeedService")
+ at AutoCreate
+public class ShotokuFeedService {
+ @In
+ private LinkService linkService;
+
+ private void setEnclosureUrl(ShotokuFeed feed, Enclosure enclosure, String nodeName) {
+ enclosure.setUrl(linkService.getServerAddress() + '/' + feed.getPodcastPrefix() + '/' + nodeName);
+ }
+
+ public void refreshEnclosureLinks(ShotokuFeed feed) {
+ for (Post post : feed.getPosts()) {
+ for (Enclosure enclosure : post.getEnclosures()) {
+ String currentUrl = enclosure.getUrl();
+ if (currentUrl != null) {
+ int lastSlash = currentUrl.lastIndexOf('/');
+ if ((lastSlash != -1) && (lastSlash != currentUrl.length()-1)) {
+ setEnclosureUrl(feed, enclosure, currentUrl.substring(lastSlash+1));
+ }
+ }
+ }
+ }
+ }
+
+ public List<Post> getPosts(ShotokuFeed feed) throws ShotokuException, PostContentTooLargeException {
+ try {
+ ContentManager cm = ContentManager.getContentManager(feed.getCmId(), feed.getCmPath());
+
+ List<Post> posts = new ArrayList<Post>();
+
+ if (cm == null) {
+ throw new ShotokuException("Couldn't initialize the specified content manager.");
+ }
+
+ Directory rootDir = cm.getRootDirectory();
+ if (rootDir == null) {
+ throw new ShotokuException("Couldn't get the root directory in the specified content manager.");
+ }
+
+ for (Node node : cm.getRootDirectory().getNodes()) {
+ Post post = new Post();
+
+ post.setAuthor(node.getProperty("author"));
+ post.setCategories(new ArrayList<Category>());
+ post.setEnclosures(new ArrayList<Enclosure>());
+ post.setImages(new ArrayList<Image>());
+ post.setModified(node.getLastModificationDate());
+ post.setPublished(node.getCreatedDate());
+ post.setTitle(node.getProperty("title"));
+
+ if (!StringTools.isEmpty(feed.getPodcastPrefix())) {
+ post.setContent(node.getProperty("description"));
+
+ Enclosure enclosure = new Enclosure(post, null, node.getLength(), node.getMimeType());
+ setEnclosureUrl(feed, enclosure, node.getName());
+ post.getEnclosures().add(enclosure);
+
+ String thumbnail = node.getProperty("thumbnail");
+ if (!StringTools.isEmpty(thumbnail)) {
+ post.getImages().add(new Image(post, linkService.getServerAddress() + '/' + thumbnail));
+ }
+ } else {
+ if (node.getLength() > 1000000) {
+ throw new PostContentTooLargeException("The content for node: '" + node.getFullName() +
+ "' is too large for a post.");
+ }
+
+ post.setContent(node.getContent());
+ }
+
+ posts.add(post);
+ }
+
+ Collections.sort(posts);
+
+ return posts;
+ } catch (RepositoryException e) {
+ throw new ShotokuException(e);
+ }
+ }
+}
Added: feeds100P26/src/shotoku/org/jboss/shotoku/web/ShotokuFilesystemResourceResolver.java
===================================================================
--- feeds100P26/src/shotoku/org/jboss/shotoku/web/ShotokuFilesystemResourceResolver.java (rev 0)
+++ feeds100P26/src/shotoku/org/jboss/shotoku/web/ShotokuFilesystemResourceResolver.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,32 @@
+package org.jboss.shotoku.web;
+
+import com.sun.facelets.impl.ResourceResolver;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.jboss.shotoku.ContentManager;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class ShotokuFilesystemResourceResolver implements ResourceResolver {
+ private String sourceBasePath;
+
+ public String getSourceBasePath() {
+ if (sourceBasePath == null) {
+ sourceBasePath = ContentManager.getProperty("shotoku.default.localpath") + "/feeds/view";
+ }
+
+ return sourceBasePath;
+ }
+
+ public URL resolveUrl(String s) {
+ try {
+ return new URL("file", "", getSourceBasePath() + s);
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+}
\ No newline at end of file
Added: feeds100P26/src/shotoku/org/jboss/shotoku/web/ShotokuResourcesFilter.java
===================================================================
--- feeds100P26/src/shotoku/org/jboss/shotoku/web/ShotokuResourcesFilter.java (rev 0)
+++ feeds100P26/src/shotoku/org/jboss/shotoku/web/ShotokuResourcesFilter.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,186 @@
+/******************************************************************************
+ * JBoss, a division of Red Hat *
+ * Copyright 2006, Red Hat Middleware, LLC, and individual *
+ * contributors as indicated by the @authors tag. See the *
+ * copyright.txt in the distribution for a full listing of *
+ * individual contributors. *
+ * *
+ * This is free software; you can redistribute it and/or modify it *
+ * under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation; either version 2.1 of *
+ * the License, or (at your option) any later version. *
+ * *
+ * This software is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with this software; if not, write to the Free *
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org. *
+ ******************************************************************************/
+package org.jboss.shotoku.web;
+
+import org.jboss.shotoku.ContentManager;
+import org.jboss.shotoku.Node;
+import org.jboss.shotoku.exceptions.ResourceDoesNotExist;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import java.io.*;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Arrays;
+import java.util.logging.Logger;
+
+/**
+ * A filter, which reads resources from the filesystem and makes them visible to the
+ * application as deployed files --- useful for development. Specifically,
+ * the <code>sourceBasePath</code> init-parameter value
+ * is prepended to the path. The file referenced by the path is then included
+ * in the request. To specify for which file extensions the filter is enabled,
+ * set the <code>extensions</code> init parameter. If not set, it defaults to:
+ * <code>jsp,css,html,htm,gif,jpg,jpeg,png,txt,xhtml</code>.
+ *
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class ShotokuResourcesFilter implements Filter {
+ private final static Logger log = Logger.getLogger(ResourcesFilter.class.getName());
+
+ /**
+ * A list of extensions, which are filtered by default, if nothing is
+ * specified in the filter configuration.
+ */
+ private final static String DEFAULT_EXTENSIONS = "jsp,css,html,htm,gif,jpg,jpeg,png,txt";
+
+ /**
+ * Base path to a directory where files will
+ * be copied; it's a subdirectory of a deployment directory created by the
+ * app server.
+ */
+ private String destBasePath;
+
+ /**
+ * A set of <code>java.lang.String</code>s, which are extensions, that are filtered.
+ */
+ private Set<String> extensions;
+
+ private ContentManager cm;
+
+ /**
+ * Transfers all bytes from the given input stream to the given output
+ * stream.
+ *
+ * @param is
+ * Input stream to read from.
+ * @param os
+ * Output stream to write to.
+ * @throws java.io.IOException In case of an IO exception.
+ */
+ private void transfer(InputStream is, OutputStream os) throws IOException {
+ byte[] buffer = new byte[1024];
+ int read;
+ while ((read = is.read(buffer)) != -1) {
+ os.write(buffer, 0, read);
+ }
+ }
+
+ public void init(FilterConfig conf) {
+ cm = ContentManager.getContentManager("default", "/feeds/view");
+
+ destBasePath = conf.getServletContext().getRealPath("");
+
+ extensions = new HashSet<String>();
+ String filteredExtensionsString = DEFAULT_EXTENSIONS;
+ String[] tokens = filteredExtensionsString.split(",");
+ extensions.addAll(Arrays.asList(tokens));
+ }
+
+ private String safeToString(Object o) {
+ if (o == null) {
+ return null;
+ }
+
+ return o.toString();
+ }
+
+ private boolean checkExtension(String path) {
+ int dotIndex = path.lastIndexOf('.');
+
+ if (dotIndex != -1) {
+ String extension = path.substring(dotIndex + 1);
+ return extensions.contains(extension);
+ } else {
+ return false;
+ }
+ }
+
+ public void doFilter(ServletRequest request, ServletResponse response,
+ FilterChain chain) throws IOException, ServletException {
+ if (request instanceof HttpServletRequest) {
+ HttpServletRequest httpRequest = (HttpServletRequest) request;
+
+ /* Getting the name of the requested resource; first checking if
+ * it is an included, then forwarded resource. Finally, checking
+ * the request uri itself. */
+ String requestedResource;
+ requestedResource = safeToString(httpRequest.getAttribute("javax.servlet.include.servlet_path"));
+
+ if (requestedResource == null) {
+ requestedResource = httpRequest.getServletPath();
+ }
+
+ // JSF check - we have to replace .jsf with .jsp.
+ String realRequestedResource = requestedResource;
+ if (realRequestedResource.endsWith(".jsf")) {
+ realRequestedResource = realRequestedResource.replace(".jsf", ".jsp");
+ }
+
+ // Filtering only some file extensions. Not filtering Seam's debug.xhtml.
+ if (!checkExtension(realRequestedResource)) {
+ chain.doFilter(request, response);
+ return;
+ }
+
+ Node sourceNode;
+ try {
+ sourceNode = cm.getNode(realRequestedResource);
+ } catch (ResourceDoesNotExist resourceDoesNotExist) {
+ chain.doFilter(request, response);
+ return;
+ }
+
+ File destFile = new File(destBasePath + realRequestedResource);
+
+ InputStream in = null;
+ OutputStream out = null;
+
+ try {
+ destFile.getParentFile().mkdirs();
+ destFile.setLastModified(System.currentTimeMillis());
+
+ in = sourceNode.getContentInputStream();
+ out = new FileOutputStream(destFile);
+
+ transfer(in, out);
+ } catch (Exception e) {
+ log.warning("Cannot copy resource: " + sourceNode);
+ } finally {
+ if (in != null) {
+ in.close();
+ }
+
+ if (out != null) {
+ out.close();
+ }
+ }
+ }
+
+ chain.doFilter(request, response);
+ }
+
+ public void destroy() {
+
+ }
+}
\ No newline at end of file
Added: feeds100P26/src/test/org/jboss/blog/session/feed/posts/AggregatedFeedPostsTest.java
===================================================================
--- feeds100P26/src/test/org/jboss/blog/session/feed/posts/AggregatedFeedPostsTest.java (rev 0)
+++ feeds100P26/src/test/org/jboss/blog/session/feed/posts/AggregatedFeedPostsTest.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,156 @@
+package org.jboss.blog.session.feed.posts;
+
+import static org.easymock.EasyMock.*;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.jboss.blog.model.feed.AggregatedFeed;
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.Post;
+import org.jboss.blog.model.RestrictedPost;
+import org.jboss.blog.model.post.PostFilter;
+import org.jboss.blog.service.FeedsService;
+import org.jboss.blog.tools.TestTools;
+import org.jboss.blog.model.post.filter.TotalFilter;
+
+import java.util.*;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class AggregatedFeedPostsTest {
+ private Feed feed_0_posts;
+ private Feed feed_1_posts;
+ private Feed feed_2_posts;
+ private Feed feed_3_posts;
+ private Feed feed_4_posts;
+
+ private List<Post> list_0_posts;
+ private List<Post> list_1_posts;
+ private List<Post> list_2_posts;
+ private List<Post> list_3_posts;
+ private List<Post> list_4_posts;
+
+ private AggregatedFeed aggFeed1;
+ private AggregatedFeed aggFeed2;
+
+ private FeedsService mockFeedsService;
+ private AggregatedFeedPosts aggFeedPosts;
+
+ private void addPosts(List<Post> posts, int count) {
+ for (int i=0; i<count; i++) {
+ posts.add(new Post());
+ }
+ }
+
+ @BeforeMethod
+ public void setupFeeds() {
+ feed_0_posts = new Feed(); feed_0_posts.setId(0);
+ feed_1_posts = new Feed(); feed_1_posts.setId(1);
+ feed_2_posts = new Feed(); feed_2_posts.setId(2);
+ feed_3_posts = new Feed(); feed_3_posts.setId(3);
+ feed_4_posts = new Feed(); feed_4_posts.setId(4);
+
+ list_0_posts = new ArrayList<Post>();
+ list_1_posts = new ArrayList<Post>();
+ list_2_posts = new ArrayList<Post>();
+ list_3_posts = new ArrayList<Post>();
+ list_4_posts = new ArrayList<Post>();
+
+ addPosts(list_0_posts, 0);
+ addPosts(list_1_posts, 1);
+ addPosts(list_2_posts, 2);
+ addPosts(list_3_posts, 3);
+ addPosts(list_4_posts, 4);
+
+ aggFeed1 = new AggregatedFeed();
+ Map<Feed, PostFilter> feedsFilters1 = new HashMap<Feed, PostFilter>();
+ feedsFilters1.put(feed_0_posts, new TotalFilter());
+ feedsFilters1.put(feed_1_posts, new TotalFilter());
+ feedsFilters1.put(feed_2_posts, new TotalFilter());
+ feedsFilters1.put(feed_3_posts, new TotalFilter());
+ feedsFilters1.put(feed_4_posts, new TotalFilter());
+ aggFeed1.setFeeds(feedsFilters1);
+ aggFeed1.setGlobalFilter(new TotalFilter());
+
+ aggFeed2 = new AggregatedFeed();
+ aggFeed2.setFeeds(feedsFilters1);
+ aggFeed2.setGlobalFilter(new PostFilter() {
+ private static final long serialVersionUID = 8320081945645277412L;
+ public boolean filter(RestrictedPost post) {
+ return false;
+ }
+ });
+ }
+
+ @BeforeMethod
+ public void setupMocks() throws IllegalAccessException, NoSuchFieldException {
+ aggFeedPosts = new AggregatedFeedPosts();
+ mockFeedsService = createMock(FeedsService.class);
+
+ TestTools.setField(aggFeedPosts, "feedsService", mockFeedsService);
+ }
+
+ @Test
+ public void testGetLessThanAvailable() {
+ // Setup
+ expect(mockFeedsService.getPosts(feed_0_posts, 0, 2)).andReturn(new ArrayList(list_0_posts));
+ expect(mockFeedsService.getPosts(feed_1_posts, 0, 2)).andReturn(new ArrayList(list_1_posts));
+ expect(mockFeedsService.getPosts(feed_2_posts, 0, 2)).andReturn(new ArrayList(list_2_posts));
+ expect(mockFeedsService.getPosts(feed_3_posts, 0, 2)).andReturn(new ArrayList(list_2_posts));
+ expect(mockFeedsService.getPosts(feed_4_posts, 0, 2)).andReturn(new ArrayList(list_2_posts));
+
+ // Test
+ replay(mockFeedsService);
+ List<? extends RestrictedPost> posts = aggFeedPosts.getPosts(aggFeed1, 0, 2, false);
+
+ // Check
+ verify(mockFeedsService);
+ assert posts.size() == 2;
+ }
+
+ @Test
+ public void testGetExactlyAvailable() {
+ // Setup
+ expect(mockFeedsService.getPosts(feed_0_posts, 0, 10)).andReturn(new ArrayList(list_0_posts));
+ expect(mockFeedsService.getPosts(feed_1_posts, 0, 10)).andReturn(new ArrayList(list_1_posts));
+ expect(mockFeedsService.getPosts(feed_2_posts, 0, 10)).andReturn(new ArrayList(list_2_posts));
+ expect(mockFeedsService.getPosts(feed_3_posts, 0, 10)).andReturn(new ArrayList(list_3_posts));
+
+ // TODO: why not ArrayList<Post>?
+
+ expect(mockFeedsService.getPosts(feed_4_posts, 0, 10)).andReturn(new ArrayList(list_4_posts));
+
+ // Test
+ replay(mockFeedsService);
+ List<? extends RestrictedPost> posts = aggFeedPosts.getPosts(aggFeed1, 0, 10, false);
+
+ // Check
+ verify(mockFeedsService);
+ assert posts.size() == 10;
+ }
+
+ @Test
+ public void testGetMoreThanAvailable() {
+ // Setup
+ expect(mockFeedsService.getPosts(feed_0_posts, 0, 2)).andReturn(new ArrayList(list_0_posts));
+ expect(mockFeedsService.getPosts(feed_1_posts, 0, 2)).andReturn(new ArrayList(list_1_posts));
+ expect(mockFeedsService.getPosts(feed_2_posts, 0, 2)).andReturn(new ArrayList(list_2_posts));
+ expect(mockFeedsService.getPosts(feed_3_posts, 0, 2)).andReturn(new ArrayList(list_2_posts));
+ expect(mockFeedsService.getPosts(feed_4_posts, 0, 2)).andReturn(new ArrayList(list_2_posts));
+
+ expect(mockFeedsService.getPosts(feed_2_posts, 2, 4)).andReturn(new ArrayList(list_0_posts));
+ expect(mockFeedsService.getPosts(feed_3_posts, 2, 4)).andReturn(new ArrayList(list_1_posts));
+ expect(mockFeedsService.getPosts(feed_4_posts, 2, 4)).andReturn(new ArrayList(list_2_posts));
+
+ expect(mockFeedsService.getPosts(feed_4_posts, 4, 6)).andReturn(new ArrayList(list_0_posts));
+
+ // Test
+ replay(mockFeedsService);
+ List<? extends RestrictedPost> posts = aggFeedPosts.getPosts(aggFeed2, 0, 2, false);
+
+ // Check
+ verify(mockFeedsService);
+ assert posts.size() == 0;
+ }
+}
Added: feeds100P26/src/test/org/jboss/blog/session/merge/test/GenericsExample1.java
===================================================================
--- feeds100P26/src/test/org/jboss/blog/session/merge/test/GenericsExample1.java (rev 0)
+++ feeds100P26/src/test/org/jboss/blog/session/merge/test/GenericsExample1.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,35 @@
+package org.jboss.blog.session.merge.test;
+
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class GenericsExample1<T> {
+ public static <E> GenericsExample1<E> getInstance(E example) {
+ return new GenericsExample1<E>();
+ }
+
+ public void process(T example) { }
+
+ public static void test(List<? extends Number> list1, List<Long> list2) {
+ //GenericsExample1.getInstance(list1).process(list2);
+ }
+
+ public static void test2(List<Long> list2) {
+ new GenericsExample1<List<? extends Number>>().process(list2);
+ }
+
+ public static void test2(List<? extends Number> list1, List<Long> list2) {
+ GenericsExample1<List<? extends Number>> x = new GenericsExample1<List<? extends Number>>();
+ //GenericsExample1<List<? extends Number>> y = getInstance(list1);
+ }
+
+ //
+
+ public void test3(List<? extends Number> list1) { }
+
+ public void test4(List<Long> list2) {
+ test3(list2);
+ }
+}
Added: feeds100P26/src/test/org/jboss/blog/session/merge/test/MergeServiceTest.java
===================================================================
--- feeds100P26/src/test/org/jboss/blog/session/merge/test/MergeServiceTest.java (rev 0)
+++ feeds100P26/src/test/org/jboss/blog/session/merge/test/MergeServiceTest.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,281 @@
+package org.jboss.blog.session.merge.test;
+
+import static org.easymock.EasyMock.*;
+import org.easymock.EasyMock;
+import org.jboss.blog.model.feed.Feed;
+import org.jboss.blog.model.Post;
+import org.jboss.blog.model.Enclosure;
+import org.jboss.blog.model.Image;
+import org.jboss.blog.model.RestrictedPost;
+import org.jboss.blog.service.FeedsService;
+import org.jboss.blog.service.PostNotFoundException;
+import org.jboss.blog.session.merge.MergeServiceBean;
+import org.jboss.blog.tools.TestTools;
+import org.jboss.seam.log.Log;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import javax.persistence.EntityManager;
+import java.util.*;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class MergeServiceTest {
+ private MergeServiceBean mergeServiceBean;
+
+ private Post post_2007_11_01_t1_c1_l1;
+ private Post post_2007_11_01_t2_c2_l2;
+ private Post post_2007_11_02_t3_c3_l3;
+ private Post post_2007_11_02_t1_c1_l4;
+ private Post post_2007_11_03_t4_c4_l5;
+ private Post post_2007_11_03_t5_c5_l6;
+ private Post post_2007_11_03_t6_c6_l6;
+ private Post post_2007_11_04_t6_c6_l7;
+ private Post post_2007_11_05_t6_c6_l8;
+
+ private EntityManager mockEntityManager;
+ private FeedsService mockFeedsService;
+
+ private Feed feed;
+
+ private Post createPost(Date published, String title, String content, String link) {
+ Post post = new Post();
+ post.setPublished(published);
+ post.setModified(published);
+ post.setTitle(title);
+ post.setContent(content);
+ post.setLink(link);
+ post.setEnclosures(new ArrayList<Enclosure>());
+ post.setImages(new ArrayList<Image>());
+
+ return post;
+ }
+
+ private Date createDate(int year, int month, int day) {
+ Calendar cal = Calendar.getInstance();
+ cal.set(year, month, day, 0, 0, 0);
+
+ return cal.getTime();
+ }
+
+ @BeforeClass
+ public void setupClass() {
+ mergeServiceBean = new MergeServiceBean();
+ }
+
+ @BeforeMethod
+ public void setupPosts() {
+ post_2007_11_01_t1_c1_l1 = createPost(createDate(2007, 11, 1), "title1", "content1", "link1");
+ post_2007_11_01_t2_c2_l2 = createPost(createDate(2007, 11, 1), "title2", "content2", "link2");
+ post_2007_11_02_t3_c3_l3 = createPost(createDate(2007, 11, 2), "title3", "content3", "link3");
+ post_2007_11_02_t1_c1_l4 = createPost(createDate(2007, 11, 2), "title1", "content1", "link4");
+ post_2007_11_03_t4_c4_l5 = createPost(createDate(2007, 11, 3), "title4", "content4", "link5");
+ post_2007_11_03_t5_c5_l6 = createPost(createDate(2007, 11, 3), "title5", "content5", "link6");
+ post_2007_11_03_t6_c6_l6 = createPost(createDate(2007, 11, 3), "title6", "content6", "link6");
+ post_2007_11_04_t6_c6_l7 = createPost(createDate(2007, 11, 4), "title6", "content6", "link7");
+ post_2007_11_05_t6_c6_l8 = createPost(createDate(2007, 11, 5), "title6", "content6", "link8");
+ }
+
+ @BeforeMethod
+ public void setupMocks() throws IllegalAccessException, NoSuchFieldException {
+ mockEntityManager = createMock(EntityManager.class);
+ TestTools.setField(mergeServiceBean, "entityManager", mockEntityManager);
+
+ mockFeedsService = createMock(FeedsService.class);
+ TestTools.setField(mergeServiceBean, "feedsService", mockFeedsService);
+
+ TestTools.setField(mergeServiceBean, "titleAsIdService", new MockTitleAsIdService());
+
+ TestTools.setField(mergeServiceBean, "log", createMock(Log.class));
+
+ TestTools.setField(mergeServiceBean, "events", new MockEvents());
+
+ feed = new Feed();
+ }
+
+ @Test
+ public void testMergeIdentical() throws IllegalAccessException, NoSuchFieldException, PostNotFoundException {
+ List<Post> posts = Arrays.asList(post_2007_11_02_t3_c3_l3,
+ post_2007_11_01_t1_c1_l1);
+
+ // Behaviour of mocks
+ EasyMock.<List<? extends RestrictedPost>>expect(mockFeedsService.getPosts(feed, 0, 3))
+ .andReturn(posts);
+ expect(mockFeedsService.getPost(post_2007_11_02_t3_c3_l3.getTitle())).andReturn(post_2007_11_02_t3_c3_l3);
+ expect(mockFeedsService.getPost(post_2007_11_01_t1_c1_l1.getTitle())).andReturn(post_2007_11_01_t1_c1_l1);
+ mockEntityManager.flush();
+
+ // Test
+ replay(mockEntityManager);
+ replay(mockFeedsService);
+
+ mergeServiceBean.merge(feed, posts);
+
+ verify(mockEntityManager);
+ verify(mockFeedsService);
+ }
+
+ @Test
+ public void testMergeToEmpty() throws IllegalAccessException, NoSuchFieldException {
+ List<Post> mergeTo = new ArrayList<Post>();
+ List<Post> mergeFrom = Arrays.asList(post_2007_11_02_t3_c3_l3,
+ post_2007_11_01_t1_c1_l1);
+
+ // Behaviour of mocks
+ EasyMock.<List<? extends RestrictedPost>>expect(mockFeedsService.getPosts(feed, 0, 3)).andReturn(mergeTo);
+ mockEntityManager.persist(post_2007_11_02_t3_c3_l3);
+ mockEntityManager.flush();
+ mockEntityManager.persist(post_2007_11_01_t1_c1_l1);
+ mockEntityManager.flush();
+ mockEntityManager.flush();
+
+ // Test
+ replay(mockEntityManager);
+ replay(mockFeedsService);
+
+ mergeServiceBean.merge(feed, mergeFrom);
+
+ verify(mockEntityManager);
+ verify(mockFeedsService);
+ }
+
+ @Test
+ public void testMergeFromEmpty() throws IllegalAccessException, NoSuchFieldException {
+ List<Post> mergeTo = Arrays.asList(post_2007_11_02_t3_c3_l3,
+ post_2007_11_01_t1_c1_l1);
+ List<Post> mergeFrom = new ArrayList<Post>();
+
+ // Behaviour of mocks
+ EasyMock.<List<? extends RestrictedPost>>expect(mockFeedsService.getPosts(feed, 0, 1)).andReturn(mergeTo);
+ mockEntityManager.flush();
+
+ // Test
+ replay(mockEntityManager);
+ replay(mockFeedsService);
+
+ mergeServiceBean.merge(feed, mergeFrom);
+
+ verify(mockEntityManager);
+ verify(mockFeedsService);
+ }
+
+ @Test
+ public void testMergeInterleaving_WithoutIntersection() throws IllegalAccessException, NoSuchFieldException {
+ List<Post> mergeTo = Arrays.asList(post_2007_11_05_t6_c6_l8,
+ post_2007_11_03_t4_c4_l5, post_2007_11_01_t1_c1_l1);
+ List<Post> mergeFrom = Arrays.asList(post_2007_11_04_t6_c6_l7,
+ post_2007_11_02_t1_c1_l4);
+
+ // Behaviour of mocks
+ EasyMock.<List<? extends RestrictedPost>>expect(mockFeedsService.getPosts(feed, 0, 3)).andReturn(mergeTo);
+ mockEntityManager.persist(post_2007_11_04_t6_c6_l7);
+ mockEntityManager.flush();
+ mockEntityManager.persist(post_2007_11_02_t1_c1_l4);
+ mockEntityManager.flush();
+ mockEntityManager.flush();
+
+ // Test
+ replay(mockEntityManager);
+ replay(mockFeedsService);
+
+ mergeServiceBean.merge(feed, mergeFrom);
+
+ verify(mockEntityManager);
+ verify(mockFeedsService);
+ }
+
+ @Test
+ public void testMergeInterleaving_WithIntersection() throws IllegalAccessException, NoSuchFieldException, PostNotFoundException {
+ List<Post> mergeTo = Arrays.asList(post_2007_11_05_t6_c6_l8,
+ post_2007_11_04_t6_c6_l7, post_2007_11_02_t1_c1_l4,
+ post_2007_11_01_t1_c1_l1);
+ List<Post> mergeFrom = Arrays.asList(post_2007_11_04_t6_c6_l7,
+ post_2007_11_03_t5_c5_l6, post_2007_11_01_t2_c2_l2);
+
+ // Behaviour of mocks
+ EasyMock.<List<? extends RestrictedPost>>expect(mockFeedsService.getPosts(feed, 0, 4)).andReturn(mergeTo);
+
+ expect(mockFeedsService.getPost(post_2007_11_04_t6_c6_l7.getTitle())).andReturn(post_2007_11_04_t6_c6_l7);
+
+ mockEntityManager.persist(post_2007_11_03_t5_c5_l6);
+ mockEntityManager.flush();
+
+ expect(mockFeedsService.getPost(post_2007_11_01_t1_c1_l1.getTitle())).andReturn(post_2007_11_01_t1_c1_l1);
+ mockEntityManager.flush();
+
+ EasyMock.<List<? extends RestrictedPost>>expect(mockFeedsService.getPosts(feed, 4, 8)).andReturn(new ArrayList<Post>());
+
+ mockEntityManager.flush();
+
+ // Test
+ replay(mockEntityManager);
+ replay(mockFeedsService);
+
+ mergeServiceBean.merge(feed, mergeFrom);
+
+ assert "title2".equals(mergeTo.get(3).getTitle());
+ assert "content2".equals(mergeTo.get(3).getContent());
+ assert "link2".equals(mergeTo.get(3).getLink());
+
+ verify(mockEntityManager);
+ verify(mockFeedsService);
+ }
+
+ @Test
+ public void testMergeChangedPost() throws IllegalAccessException, NoSuchFieldException, PostNotFoundException {
+ List<Post> mergeTo = Arrays.asList(post_2007_11_05_t6_c6_l8,
+ post_2007_11_04_t6_c6_l7, post_2007_11_03_t5_c5_l6,
+ post_2007_11_03_t4_c4_l5, post_2007_11_02_t3_c3_l3);
+ List<Post> mergeFrom = Arrays.asList(post_2007_11_05_t6_c6_l8,
+ post_2007_11_04_t6_c6_l7, post_2007_11_03_t6_c6_l6,
+ post_2007_11_03_t4_c4_l5, post_2007_11_02_t3_c3_l3);
+
+ // Behaviour of mocks
+ EasyMock.<List<? extends RestrictedPost>>expect(mockFeedsService.getPosts(feed, 0, 6)).andReturn(mergeTo);
+ expect(mockFeedsService.getPost(post_2007_11_05_t6_c6_l8.getTitle())).andReturn(post_2007_11_05_t6_c6_l8);
+ expect(mockFeedsService.getPost(post_2007_11_04_t6_c6_l7.getTitle())).andReturn(post_2007_11_04_t6_c6_l7);
+ expect(mockFeedsService.getPost(post_2007_11_03_t5_c5_l6.getTitle())).andReturn(post_2007_11_03_t5_c5_l6);
+ expect(mockFeedsService.getPost(post_2007_11_03_t4_c4_l5.getTitle())).andReturn(post_2007_11_03_t4_c4_l5);
+ expect(mockFeedsService.getPost(post_2007_11_02_t3_c3_l3.getTitle())).andReturn(post_2007_11_02_t3_c3_l3);
+ mockEntityManager.flush();
+ mockEntityManager.flush();
+
+ // Test
+ replay(mockEntityManager);
+ replay(mockFeedsService);
+
+ mergeServiceBean.merge(feed, mergeFrom);
+ assert "title6".equals(mergeTo.get(2).getTitle());
+ assert "content6".equals(mergeTo.get(2).getContent());
+
+ verify(mockEntityManager);
+ verify(mockFeedsService);
+ }
+
+ @Test
+ public void testMergeOld() throws IllegalAccessException, NoSuchFieldException {
+ List<Post> mergeTo1 = Arrays.asList(post_2007_11_05_t6_c6_l8, post_2007_11_04_t6_c6_l7);
+ List<Post> mergeTo2 = Arrays.asList(post_2007_11_03_t5_c5_l6, post_2007_11_03_t4_c4_l5);
+ List<Post> mergeTo3 = Arrays.asList(post_2007_11_01_t1_c1_l1);
+ List<Post> mergeFrom = Arrays.asList(post_2007_11_02_t1_c1_l4);
+
+ // Behaviour of mocks
+ EasyMock.<List<? extends RestrictedPost>>expect(mockFeedsService.getPosts(feed, 0, 2)).andReturn(mergeTo1);
+ EasyMock.<List<? extends RestrictedPost>>expect(mockFeedsService.getPosts(feed, 2, 4)).andReturn(mergeTo2);
+ EasyMock.<List<? extends RestrictedPost>>expect(mockFeedsService.getPosts(feed, 4, 6)).andReturn(mergeTo3);
+ mockEntityManager.persist(post_2007_11_02_t1_c1_l4);
+ mockEntityManager.flush();
+ mockEntityManager.flush();
+
+ // Test
+ replay(mockEntityManager);
+ replay(mockFeedsService);
+
+ mergeServiceBean.merge(feed, mergeFrom);
+
+ verify(mockEntityManager);
+ verify(mockFeedsService);
+ }
+}
Added: feeds100P26/src/test/org/jboss/blog/session/merge/test/MockEvents.java
===================================================================
--- feeds100P26/src/test/org/jboss/blog/session/merge/test/MockEvents.java (rev 0)
+++ feeds100P26/src/test/org/jboss/blog/session/merge/test/MockEvents.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,12 @@
+package org.jboss.blog.session.merge.test;
+
+import org.jboss.seam.core.Events;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class MockEvents extends Events {
+ public void raiseEvent(String s, Object... objects) {
+
+ }
+}
Added: feeds100P26/src/test/org/jboss/blog/session/merge/test/MockTitleAsIdService.java
===================================================================
--- feeds100P26/src/test/org/jboss/blog/session/merge/test/MockTitleAsIdService.java (rev 0)
+++ feeds100P26/src/test/org/jboss/blog/session/merge/test/MockTitleAsIdService.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,13 @@
+package org.jboss.blog.session.merge.test;
+
+import org.jboss.blog.session.merge.TitleAsIdService;
+import org.jboss.blog.tools.StringTools;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class MockTitleAsIdService implements TitleAsIdService {
+ public String generateTitleAsId(String title) {
+ return StringTools.convertTitleToLink(title);
+ }
+}
Added: feeds100P26/src/test/org/jboss/blog/session/parser/RomeExample.java
===================================================================
--- feeds100P26/src/test/org/jboss/blog/session/parser/RomeExample.java (rev 0)
+++ feeds100P26/src/test/org/jboss/blog/session/parser/RomeExample.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,29 @@
+package org.jboss.blog.session.parser;
+
+import com.sun.syndication.io.SyndFeedInput;
+import com.sun.syndication.io.XmlReader;
+import com.sun.syndication.io.FeedException;
+import com.sun.syndication.feed.synd.SyndFeed;
+import com.sun.syndication.feed.synd.SyndEntry;
+
+import java.net.URL;
+import java.net.MalformedURLException;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class RomeExample {
+ public static void main(String[] args) throws IOException, FeedException {
+ SyndFeedInput input = new SyndFeedInput();
+ SyndFeed syndFeed = input.build(new XmlReader(new URL("http://labs.jboss.com/feeds/jbosslabs/podcast/rss2")));
+
+ List entries = syndFeed.getEntries();
+
+ SyndEntry entry = (SyndEntry) entries.get(0);
+ List enclosures = entry.getEnclosures();
+
+ System.out.println(syndFeed.getTitle());
+ }
+}
Added: feeds100P26/src/test/org/jboss/blog/session/parser/RomeExample2.java
===================================================================
--- feeds100P26/src/test/org/jboss/blog/session/parser/RomeExample2.java (rev 0)
+++ feeds100P26/src/test/org/jboss/blog/session/parser/RomeExample2.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,29 @@
+package org.jboss.blog.session.parser;
+
+import com.sun.syndication.io.SyndFeedInput;
+import com.sun.syndication.io.XmlReader;
+import com.sun.syndication.io.FeedException;
+import com.sun.syndication.feed.synd.SyndFeed;
+import com.sun.syndication.feed.synd.SyndEntry;
+
+import java.net.URL;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class RomeExample2 {
+ public static void main(String[] args) throws IOException, FeedException {
+ SyndFeedInput input = new SyndFeedInput();
+ SyndFeed syndFeed = input.build(
+ new XmlReader(new URL("http://rss.cnn.com/services/podcasting/newscast/rss.xml")));
+
+ List entries = syndFeed.getEntries();
+
+ SyndEntry entry = (SyndEntry) entries.get(0);
+ List x = (List) entry.getForeignMarkup();
+
+ System.out.println(x.get(0).getClass().getName());
+ }
+}
\ No newline at end of file
Added: feeds100P26/src/test/org/jboss/blog/session/parser/RomeExample3.java
===================================================================
--- feeds100P26/src/test/org/jboss/blog/session/parser/RomeExample3.java (rev 0)
+++ feeds100P26/src/test/org/jboss/blog/session/parser/RomeExample3.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,31 @@
+package org.jboss.blog.session.parser;
+
+import com.sun.syndication.io.SyndFeedInput;
+import com.sun.syndication.io.XmlReader;
+import com.sun.syndication.io.FeedException;
+import com.sun.syndication.feed.synd.SyndFeed;
+import com.sun.syndication.feed.synd.SyndEntry;
+import com.sun.syndication.feed.module.Module;
+
+import java.net.URL;
+import java.net.URLConnection;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class RomeExample3 {
+ public static void main(String[] args) throws IOException, FeedException, ParserException {
+ /*SyndFeedInput input = new SyndFeedInput();
+
+ URLConnection conn = new URL("http://www.warski.org/blog/?feed=rss2").openConnection();
+ conn.setReadTimeout(3000);
+ conn.setConnectTimeout(5000);
+ conn.connect();
+
+ SyndFeed syndFeed = input.build(new XmlReader(conn.getInputStream()));*/
+
+ new ParserServiceImpl().parse("http://www.warski.org/blog/?feed=rss2");
+ }
+}
\ No newline at end of file
Added: feeds100P26/src/test/org/jboss/blog/tools/FixHtmlExample1.java
===================================================================
--- feeds100P26/src/test/org/jboss/blog/tools/FixHtmlExample1.java (rev 0)
+++ feeds100P26/src/test/org/jboss/blog/tools/FixHtmlExample1.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,10 @@
+package org.jboss.blog.tools;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class FixHtmlExample1 {
+ public static void main(String[] args) {
+ System.out.println(StringTools.fixHtml("Gurkan Erdogdu and Kris Verlaenen a warm welcome in our <a href=\"http://jboss.com/index.html?module=bb&op=viewforum&f=201\">forums</a>!"));
+ }
+}
Added: feeds100P26/src/test/org/jboss/blog/tools/FixHtmlTest.java
===================================================================
--- feeds100P26/src/test/org/jboss/blog/tools/FixHtmlTest.java (rev 0)
+++ feeds100P26/src/test/org/jboss/blog/tools/FixHtmlTest.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,26 @@
+package org.jboss.blog.tools;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class FixHtmlTest {
+ @DataProvider(name = "texts")
+ public Object[][] getData() {
+ return new Object[][] {
+ { "<p>Some text.</p>", "<p>Some text.</p>\n" },
+ { "<p><i>Some text.</i></p>", "<p><i>Some text.</i>\n</p>\n" },
+ { "Some text.", "Some text." },
+ { "<p>Some text.", "<p>Some text.</p>\n" },
+ { "Some text.</p>", "Some text." }
+ };
+ }
+
+ @Test(dataProvider = "texts")
+ public void test(String original, String fixed) {
+ System.out.println(StringTools.fixHtml(original));
+ assert fixed.equals(StringTools.fixHtml(original));
+ }
+}
Added: feeds100P26/src/test/org/jboss/blog/tools/StripHtmlTest.java
===================================================================
--- feeds100P26/src/test/org/jboss/blog/tools/StripHtmlTest.java (rev 0)
+++ feeds100P26/src/test/org/jboss/blog/tools/StripHtmlTest.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,25 @@
+package org.jboss.blog.tools;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class StripHtmlTest {
+ @DataProvider(name = "texts")
+ public Object[][] getData() {
+ return new Object[][] {
+ { "<p>Some text.</p>", "Some text." },
+ { "This: < shouldn't get removed.", "This: < shouldn't get removed." },
+ { "<p>Non-terminated tags. <a> And now this!. >", "Non-terminated tags. And now this!. >" },
+ { "<p > Tags with spaces, and some <a > not terminated </a>.",
+ "Tags with spaces, and some not terminated ." }
+ };
+ }
+
+ @Test(dataProvider = "texts")
+ public void test(String original, String stripped) {
+ assert stripped.equals(StringTools.stripHtml(original));
+ }
+}
Added: feeds100P26/src/test/org/jboss/blog/tools/TestTools.java
===================================================================
--- feeds100P26/src/test/org/jboss/blog/tools/TestTools.java (rev 0)
+++ feeds100P26/src/test/org/jboss/blog/tools/TestTools.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,15 @@
+package org.jboss.blog.tools;
+
+import java.lang.reflect.Field;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class TestTools {
+ public static void setField(Object o, String fieldName, Object setTo)
+ throws NoSuchFieldException, IllegalAccessException {
+ Field f = o.getClass().getDeclaredField(fieldName);
+ f.setAccessible(true);
+ f.set(o, setTo);
+ }
+}
Added: feeds100P26/src/test/org/jboss/blog/tools/TitleToLinkTest.java
===================================================================
--- feeds100P26/src/test/org/jboss/blog/tools/TitleToLinkTest.java (rev 0)
+++ feeds100P26/src/test/org/jboss/blog/tools/TitleToLinkTest.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,33 @@
+package org.jboss.blog.tools;
+
+import org.testng.annotations.Test;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class TitleToLinkTest {
+ @Test
+ public void testEmpty() {
+ assert "".equals(StringTools.convertTitleToLink(""));
+ }
+
+ @Test
+ public void testEmpty2() {
+ assert "".equals(StringTools.convertTitleToLink("!@#$%"));
+ }
+
+ @Test
+ public void testNormal() {
+ assert "abd_ef_s_jj".equals(StringTools.convertTitleToLink("*abd**ef***s*jj*"));
+ }
+
+ @Test
+ public void testEnd() {
+ assert "aaa".equals(StringTools.convertTitleToLink("***aaa"));
+ }
+
+ @Test
+ public void testBeginning() {
+ assert "aaa".equals(StringTools.convertTitleToLink("aaa***"));
+ }
+}
Added: feeds100P26/src/tools/org/jboss/blog/tools/GeneralTools.java
===================================================================
--- feeds100P26/src/tools/org/jboss/blog/tools/GeneralTools.java (rev 0)
+++ feeds100P26/src/tools/org/jboss/blog/tools/GeneralTools.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,185 @@
+package org.jboss.blog.tools;
+
+import java.io.*;
+import java.util.List;
+import java.util.Collections;
+import java.util.Date;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class GeneralTools {
+ public static boolean objectsEqual(Object o1, Object o2) {
+ if (o1 == null) {
+ return o2 == null;
+ } else {
+ return o1.equals(o2);
+ }
+ }
+
+ private static final int TRANSFER_BUFFER_SIZE = 2048;
+
+ /**
+ * Transferes all bytes from the given input stream to the given output
+ * stream.
+ *
+ * @param is
+ * Input stream to read from.
+ * @param w
+ * Printwriter to write to.
+ * @throws java.io.IOException In case of an IO exception.
+ */
+ public static void transfer(InputStream is, Writer w) throws IOException {
+ char[] buffer = new char[TRANSFER_BUFFER_SIZE];
+ int read;
+ InputStreamReader isr = new InputStreamReader(is);
+ while ((read = isr.read(buffer)) != -1) {
+ w.write(buffer, 0, read);
+ }
+ }
+
+ /**
+ * Transferes all bytes from the given reader to the writer
+ *
+ * @param r
+ * Reader to read from.
+ * @param w
+ * Writer to write to.
+ * @throws java.io.IOException In case of an IO exception.
+ */
+ public static void transfer(Reader r, Writer w) throws IOException {
+ char[] buffer = new char[TRANSFER_BUFFER_SIZE];
+ int read;
+ while ((read = r.read(buffer)) != -1) {
+ w.write(buffer, 0, read);
+ }
+ }
+
+ /**
+ * Transferes all bytes from the given input stream to the given output
+ * stream.
+ *
+ * @param is
+ * Input stream to read from.
+ * @param os
+ * Output stream to write to.
+ * @throws IOException In case of an IO exception.
+ */
+ public static void transfer(InputStream is, OutputStream os) throws IOException {
+ byte[] buffer = new byte[TRANSFER_BUFFER_SIZE];
+ int read;
+ while ((read = is.read(buffer)) != -1) {
+ os.write(buffer, 0, read);
+ }
+ }
+
+ public static <T> int safeCompare(Comparable<T> o1, T o2) {
+ if (o1 == null) {
+ if (o2 == null) {
+ return 0;
+ }
+
+ return 1;
+ } else if (o2 == null) {
+ return -1;
+ } else {
+ return o1.compareTo(o2);
+ }
+ }
+
+ public static <T> List<T> subList(List<T> list, int from, int to) {
+ if (from > to) {
+ return Collections.emptyList();
+ }
+
+ if (from > list.size()) {
+ return Collections.emptyList();
+ }
+
+ return list.subList(from, Math.min(to, list.size()));
+ }
+
+ public static <T> void moveElement(List<T> list, int from, int to) {
+ if (from < 0 || from > list.size() || to < 0 || to > list.size()) {
+ return;
+ }
+
+ if (from == to) {
+ return;
+ }
+
+ T toMove = list.get(from);
+
+ if (from < to) {
+ int currentIndex = from;
+ while (currentIndex != to) {
+ list.set(currentIndex, list.get(currentIndex + 1));
+ currentIndex++;
+ }
+
+ list.set(to, toMove);
+ } else {
+ int currentIndex = from;
+ while (currentIndex != to) {
+ list.set(currentIndex, list.get(currentIndex - 1));
+ currentIndex--;
+ }
+
+ list.set(to, toMove);
+ }
+ }
+
+ public static int compareDates(Date date1, Date date2) {
+ long seconds1 = (date1 == null) ? 0 : (date1.getTime() / 1000);
+ long seconds2 = (date2 == null) ? 0 : (date2.getTime() / 1000);
+
+ if (seconds1 == seconds2) {
+ return 0;
+ } else if (seconds1 > seconds2) {
+ return 1;
+ } else {
+ return -1;
+ }
+ }
+
+ public static int compareStrings(String str1, String str2) {
+ if (str1 == null) {
+ if (str2 == null) {
+ return 0;
+ } else {
+ return -1;
+ }
+ } else if (str2 == null) {
+ return 1;
+ } else {
+ return str1.compareTo(str2);
+ }
+ }
+
+ public static String readInputStream(InputStream is) throws IOException {
+ StringBuffer contents = new StringBuffer();
+
+ BufferedReader input = new BufferedReader(new InputStreamReader(is));
+ try {
+ String line;
+ while ((line = input.readLine()) != null) {
+ contents.append(line);
+ contents.append(System.getProperty("line.separator"));
+ }
+ } finally {
+ input.close();
+ }
+
+ return contents.toString();
+ }
+
+ public static String getExceptionStackTrace(Exception e) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ PrintWriter pw = new PrintWriter(baos);
+
+ e.printStackTrace(pw);
+
+ pw.flush();
+ return baos.toString();
+ }
+}
Added: feeds100P26/src/tools/org/jboss/blog/tools/KeyNotMappedException.java
===================================================================
--- feeds100P26/src/tools/org/jboss/blog/tools/KeyNotMappedException.java (rev 0)
+++ feeds100P26/src/tools/org/jboss/blog/tools/KeyNotMappedException.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,21 @@
+package org.jboss.blog.tools;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class KeyNotMappedException extends RuntimeException {
+ public KeyNotMappedException() {
+ }
+
+ public KeyNotMappedException(String message) {
+ super(message);
+ }
+
+ public KeyNotMappedException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public KeyNotMappedException(Throwable cause) {
+ super(cause);
+ }
+}
Added: feeds100P26/src/tools/org/jboss/blog/tools/KeySafeMap.java
===================================================================
--- feeds100P26/src/tools/org/jboss/blog/tools/KeySafeMap.java (rev 0)
+++ feeds100P26/src/tools/org/jboss/blog/tools/KeySafeMap.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,84 @@
+package org.jboss.blog.tools;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.Collection;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class KeySafeMap<K, V> implements Map<K, V> {
+ private Map<K, V> delegate;
+
+ public KeySafeMap(Map<K, V> delegate) {
+ if (delegate == null) {
+ throw new IllegalArgumentException("Delegate map cannot be null!");
+ }
+
+ this.delegate = delegate;
+ }
+
+ public static <K, V> KeySafeMap<K, V> wrap(Map<K, V> toWrap) {
+ return new KeySafeMap<K, V>(toWrap);
+ }
+
+ public int size() {
+ return delegate.size();
+ }
+
+ public boolean isEmpty() {
+ return delegate.isEmpty();
+ }
+
+ public boolean containsKey(Object key) {
+ return delegate.containsKey(key);
+ }
+
+ public boolean containsValue(Object value) {
+ return delegate.containsValue(value);
+ }
+
+ public V get(Object key) {
+ if (containsKey(key)) {
+ return delegate.get(key);
+ } else {
+ throw new KeyNotMappedException(StringTools.safeToString(key));
+ }
+ }
+
+ public V put(K key, V value) {
+ return delegate.put(key, value);
+ }
+
+ public V remove(Object key) {
+ return delegate.remove(key);
+ }
+
+ public void putAll(Map<? extends K, ? extends V> t) {
+ delegate.putAll(t);
+ }
+
+ public void clear() {
+ delegate.clear();
+ }
+
+ public Set<K> keySet() {
+ return delegate.keySet();
+ }
+
+ public Collection<V> values() {
+ return delegate.values();
+ }
+
+ public Set<Entry<K, V>> entrySet() {
+ return delegate.entrySet();
+ }
+
+ public boolean equals(Object o) {
+ return delegate.equals(o);
+ }
+
+ public int hashCode() {
+ return delegate.hashCode();
+ }
+}
Added: feeds100P26/src/tools/org/jboss/blog/tools/Pair.java
===================================================================
--- feeds100P26/src/tools/org/jboss/blog/tools/Pair.java (rev 0)
+++ feeds100P26/src/tools/org/jboss/blog/tools/Pair.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,34 @@
+package org.jboss.blog.tools;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class Pair<T1, T2> {
+ private T1 first;
+ private T2 second;
+
+ public Pair(T1 first, T2 second) {
+ this.first = first;
+ this.second = second;
+ }
+
+ public T1 getFirst() {
+ return first;
+ }
+
+ public void setFirst(T1 first) {
+ this.first = first;
+ }
+
+ public T2 getSecond() {
+ return second;
+ }
+
+ public void setSecond(T2 second) {
+ this.second = second;
+ }
+
+ public static <T1, T2> Pair<T1,T2> createPair(T1 first, T2 second) {
+ return new Pair<T1, T2>(first, second);
+ }
+}
Added: feeds100P26/src/tools/org/jboss/blog/tools/StringTools.java
===================================================================
--- feeds100P26/src/tools/org/jboss/blog/tools/StringTools.java (rev 0)
+++ feeds100P26/src/tools/org/jboss/blog/tools/StringTools.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,237 @@
+package org.jboss.blog.tools;
+
+import au.id.jericho.lib.html.Source;
+import org.htmlcleaner.HtmlCleaner;
+import org.xml.sax.SAXException;
+import org.xml.sax.InputSource;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXParseException;
+import org.jboss.seam.log.Logging;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.IOException;
+import java.io.StringReader;
+import java.text.StringCharacterIterator;
+import java.text.CharacterIterator;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class StringTools {
+ public static boolean isEmpty(String s) {
+ return s == null || "".equals(s);
+ }
+
+ public static String safeToString(Object o) {
+ return o == null ? null : o.toString();
+ }
+
+ public static String convertTitleToLink(String title) {
+ if (title == null) {
+ return null;
+ }
+
+ char[] titleWithUnderscores = title.toLowerCase().replaceAll("[^a-z0-9_]", "_").toCharArray();
+
+ StringBuffer newTitle = new StringBuffer();
+
+ // Removing _ from the beginning.
+ int titleIndex = 0;
+ while ((titleIndex < titleWithUnderscores.length) && (titleWithUnderscores[titleIndex] == '_')) {
+ titleIndex++;
+ }
+
+ // Removing multiple _ in the text.
+ boolean previousLetter = true;
+ while (titleIndex < titleWithUnderscores.length) {
+ if (titleWithUnderscores[titleIndex] == '_') {
+ if (previousLetter) {
+ newTitle.append(titleWithUnderscores[titleIndex]);
+ }
+
+ previousLetter = false;
+ } else {
+ newTitle.append(titleWithUnderscores[titleIndex]);
+ previousLetter = true;
+ }
+
+ titleIndex++;
+ }
+
+ // Removing _ from the end, if there was one.
+ if ((newTitle.length() > 0) && (newTitle.charAt(newTitle.length()-1) == '_')) {
+ newTitle.deleteCharAt(newTitle.length()-1);
+ }
+
+ return newTitle.toString();
+ }
+
+ public static String stripHtml(String html) {
+ Source source = new Source(html);
+
+ source.fullSequentialParse();
+
+ return source.getTextExtractor().toString();
+ }
+
+ public static boolean isValidXml(String html) {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setValidating(false);
+
+ DocumentBuilder builder;
+ try {
+ builder = factory.newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ Logging.getLog(StringTools.class).error(e);
+ return false;
+ }
+
+ builder.setErrorHandler(new ErrorHandler() {
+ public void warning(SAXParseException exception) throws SAXException { throw exception; }
+ public void error(SAXParseException exception) throws SAXException { throw exception; }
+ public void fatalError(SAXParseException exception) throws SAXException { throw exception; }
+ });
+
+ try {
+ builder.parse(new InputSource(new StringReader(html)));
+ return true;
+ } catch (SAXException e) {
+ return false;
+ } catch (IOException e) {
+ Logging.getLog(StringTools.class).error(e);
+ return false;
+ }
+ }
+
+ public static String fixHtml(String html) {
+ if (isEmpty(html)) {
+ return html;
+ }
+
+ String htmlToCheck = "<div>" + html + "</div>";
+
+ if (isValidXml(htmlToCheck)) {
+ return html;
+ }
+
+ HtmlCleaner cleaner = new HtmlCleaner(htmlToCheck);
+ try {
+ cleaner.setOmitHtmlEnvelope(true);
+ cleaner.setOmitXmlDeclaration(true);
+ cleaner.setRecognizeUnicodeChars(false);
+ cleaner.setTranslateSpecialEntities(false);
+ cleaner.setAdvancedXmlEscape(true);
+ cleaner.clean();
+
+ String ret = cleaner.getXmlAsString().trim();
+
+ // Removing the <div> and </div>
+ ret = ret.substring(5);
+ ret = ret.substring(0, ret.length()-6);
+
+ return ret;
+ } catch (IOException e) {
+ return html;
+ }
+ }
+
+ public static String createSummary(String s, int length) {
+ if (s == null) {
+ return null;
+ }
+
+ s = stripHtml(s);
+
+ if (s.length() > length) {
+ s = s.substring(0, length);
+ return s + "...";
+ } else {
+ return s;
+ }
+ }
+
+ /**
+ * Escape characters for text appearing in HTML markup.
+ *
+ * <P>This method exists as a defence against Cross Site Scripting (XSS) hacks.
+ * This method escapes all characters recommended by the Open Web App
+ * Security Project -
+ * <a href='http://www.owasp.org/index.php/Cross_Site_Scripting'>link</a>.
+ *
+ * <P>The following characters are replaced with corresponding HTML
+ * character entities :
+ * <table border='1' cellpadding='3' cellspacing='0'>
+ * <tr><th> Character </th><th> Encoding </th></tr>
+ * <tr><td> < </td><td> < </td></tr>
+ * <tr><td> > </td><td> > </td></tr>
+ * <tr><td> & </td><td> & </td></tr>
+ * <tr><td> " </td><td> "</td></tr>
+ * <tr><td> ' </td><td> '</td></tr>
+ * <tr><td> ( </td><td> (</td></tr>
+ * <tr><td> ) </td><td> )</td></tr>
+ * <tr><td> # </td><td> #</td></tr>
+ * <tr><td> % </td><td> %</td></tr>
+ * <tr><td> ; </td><td> ;</td></tr>
+ * <tr><td> + </td><td> + </td></tr>
+ * <tr><td> - </td><td> - </td></tr>
+ * </table>
+ *
+ * <P>Note that JSTL's {@code <c:out>} escapes <em>only the first
+ * five</em> of the above characters.
+ *
+ * @author http://www.javapractices.com/topic/TopicAction.do;jsessionid=A293F4E3A21E476DC8488FED3DE883A0?Id=96
+ */
+ public static String escape(String toEscape){
+ final StringBuilder result = new StringBuilder();
+ final StringCharacterIterator iterator = new StringCharacterIterator(toEscape);
+ char character = iterator.current();
+ while (character != CharacterIterator.DONE ){
+ if (character == '<') {
+ result.append("<");
+ }
+ else if (character == '>') {
+ result.append(">");
+ }
+ else if (character == '&') {
+ result.append("&");
+ }
+ else if (character == '\"') {
+ result.append(""");
+ }
+ else if (character == '\'') {
+ result.append("'");
+ }
+ else if (character == '(') {
+ result.append("(");
+ }
+ else if (character == ')') {
+ result.append(")");
+ }
+ else if (character == '#') {
+ result.append("#");
+ }
+ else if (character == '%') {
+ result.append("%");
+ }
+ else if (character == ';') {
+ result.append(";");
+ }
+ else if (character == '+') {
+ result.append("+");
+ }
+ else if (character == '-') {
+ result.append("-");
+ }
+ else {
+ //the char is not a special one
+ //add it to the result as is
+ result.append(character);
+ }
+ character = iterator.next();
+ }
+ return result.toString();
+ }
+
+}
Added: feeds100P26/src/tools/org/jboss/blog/tools/search/UnrestrictedFeedFilter.java
===================================================================
--- feeds100P26/src/tools/org/jboss/blog/tools/search/UnrestrictedFeedFilter.java (rev 0)
+++ feeds100P26/src/tools/org/jboss/blog/tools/search/UnrestrictedFeedFilter.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,25 @@
+package org.jboss.blog.tools.search;
+
+import org.apache.lucene.search.Filter;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.TermDocs;
+import org.apache.lucene.index.Term;
+
+import java.util.BitSet;
+import java.io.IOException;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class UnrestrictedFeedFilter extends Filter {
+ public BitSet bits(IndexReader indexReader) throws IOException {
+ BitSet bitSet = new BitSet(indexReader.maxDoc());
+ TermDocs termDocs = indexReader.termDocs(new Term("restricted", "0"));
+
+ while (termDocs.next()) {
+ bitSet.set(termDocs.doc());
+ }
+
+ return bitSet;
+ }
+}
Added: feeds100P26/src/tools/org/jboss/blog/tools/search/bridge/FeedBridge.java
===================================================================
--- feeds100P26/src/tools/org/jboss/blog/tools/search/bridge/FeedBridge.java (rev 0)
+++ feeds100P26/src/tools/org/jboss/blog/tools/search/bridge/FeedBridge.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,22 @@
+package org.jboss.blog.tools.search.bridge;
+
+import org.hibernate.search.bridge.StringBridge;
+import org.jboss.blog.model.feed.Feed;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class FeedBridge implements StringBridge {
+ public String objectToString(Object object) {
+ if (object == null) {
+ return null;
+ }
+
+ Feed feed = (Feed) object;
+ if (feed.isFeedRestricted()) {
+ return "1";
+ } else {
+ return "0";
+ }
+ }
+}
Added: feeds100P26/src/tools/org/jboss/blog/tools/search/bridge/StripHtmlBridge.java
===================================================================
--- feeds100P26/src/tools/org/jboss/blog/tools/search/bridge/StripHtmlBridge.java (rev 0)
+++ feeds100P26/src/tools/org/jboss/blog/tools/search/bridge/StripHtmlBridge.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,17 @@
+package org.jboss.blog.tools.search.bridge;
+
+import org.hibernate.search.bridge.StringBridge;
+import org.jboss.blog.tools.StringTools;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class StripHtmlBridge implements StringBridge {
+ public String objectToString(Object o) {
+ if (o == null) {
+ return null;
+ }
+
+ return StringTools.stripHtml(o.toString());
+ }
+}
Added: feeds100P26/src/tools/org/jboss/blog/tools/validator/Regexp.java
===================================================================
--- feeds100P26/src/tools/org/jboss/blog/tools/validator/Regexp.java (rev 0)
+++ feeds100P26/src/tools/org/jboss/blog/tools/validator/Regexp.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,16 @@
+package org.jboss.blog.tools.validator;
+
+import org.hibernate.validator.ValidatorClass;
+
+import java.lang.annotation.*;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+ at ValidatorClass(RegexpValidator.class)
+ at Target({ElementType.FIELD, ElementType.METHOD})
+ at Retention(RetentionPolicy.RUNTIME)
+ at Documented
+public @interface Regexp {
+ String message() default "must be a valid regular expression";
+}
Added: feeds100P26/src/tools/org/jboss/blog/tools/validator/RegexpValidator.java
===================================================================
--- feeds100P26/src/tools/org/jboss/blog/tools/validator/RegexpValidator.java (rev 0)
+++ feeds100P26/src/tools/org/jboss/blog/tools/validator/RegexpValidator.java 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,36 @@
+package org.jboss.blog.tools.validator;
+
+import org.hibernate.validator.PropertyConstraint;
+import org.hibernate.validator.Validator;
+import org.hibernate.mapping.Property;
+
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class RegexpValidator implements Validator<Regexp>, PropertyConstraint {
+ public void initialize(Regexp parameters) { }
+
+ public boolean isValid(Object value) {
+ if (value == null) {
+ return true;
+ }
+
+ if (!(value instanceof String)) {
+ return false;
+ }
+
+ String string = (String) value;
+
+ try {
+ Pattern.compile(string);
+ return true;
+ } catch (PatternSyntaxException e) {
+ return false;
+ }
+ }
+
+ public void apply(Property property) { }
+}
\ No newline at end of file
Added: feeds100P26/view/common/ajax_status.xhtml
===================================================================
--- feeds100P26/view/common/ajax_status.xhtml (rev 0)
+++ feeds100P26/view/common/ajax_status.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,17 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j">
+ <a:status stopStyleClass="ajaxStatus" startStyleClass="ajaxStatus">
+ <f:facet name="start">
+ <img src="/feeds/images/wait.gif" alt="" /> Please wait ...
+ </f:facet>
+ <f:facet name="stop">
+ </f:facet>
+ </a:status>
+</ui:composition>
\ No newline at end of file
Added: feeds100P26/view/common/next_previous_navigation.xhtml
===================================================================
--- feeds100P26/view/common/next_previous_navigation.xhtml (rev 0)
+++ feeds100P26/view/common/next_previous_navigation.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,29 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j">
+ <s:fragment rendered="#{navigationBean.showPrevious}">
+ <li>
+ <s:link view="#{viewId}" value="« Previous" propagation="none">
+ <f:param name="from" value="#{navigationBean.previousFrom}" />
+ </s:link>
+ </li>
+ </s:fragment>
+
+ <s:fragment rendered="#{navigationBean.showNext}">
+ <li>
+ <s:link view="#{viewId}" value="Next »" rendered="#{navigationBean.showNext}" propagation="none">
+ <f:param name="from" value="#{navigationBean.nextFrom}" />
+ </s:link>
+ </li>
+ </s:fragment>
+
+ <s:fragment rendered="#{(navigationBean.showNext || navigationBean.showPrevious) and showColon}">
+ <li>:</li>
+ </s:fragment>
+</ui:composition>
\ No newline at end of file
Added: feeds100P26/view/common/post.xhtml
===================================================================
--- feeds100P26/view/common/post.xhtml (rev 0)
+++ feeds100P26/view/common/post.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,61 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j">
+ <h3>
+ <s:link value="#{post.title}" view="/view/post.xhtml" propagation="none">
+ <f:param name="post" value="#{post.titleAsId}" />
+ </s:link>
+ </h3>
+
+ <p class="blogauthortag">
+ Posted on #{post.published} by <b>#{post.effectiveAuthor}</b> #{additionalHeader}
+ [ <a href="#{post.link}">View original post</a> ]
+ <s:fragment rendered="#{showAddToHighlights and identity.hasPermission('management', 'view') and highlightsSecurity.feeds.size() > 0}">
+ [ <s:link value="Add this post to a highlights feed" view="/manage/highlights/post_add.xhtml">
+ <f:param name="post" value="#{post.titleAsId}" />
+ </s:link> ]
+ </s:fragment>
+ </p>
+
+ <ui:repeat var="image" value="#{post.images}">
+ <img src="#{image.url}" alt="#{image.title}" width="180" />
+ </ui:repeat>
+
+ <ui:repeat var="enclosure" value="#{post.enclosures}">
+ <p class="blogauthortag">
+ Enclosure: <h:outputLink value="#{enclosure.url}">#{enclosure.url}</h:outputLink>
+ </p>
+ </ui:repeat>
+
+ <h:outputText value="#{post.content}" escape="false" rendered="#{!showSummary}" />
+ <h:outputText value="#{stringTools.createSummary(post.content)}" rendered="#{showSummary}" />
+
+ <s:fragment rendered="#{showPostTo and post.feed.showDzone}">
+ <img src="http://www.dzone.com/links/themes/reader/images/actions/icon-vote.gif" alt="" />
+ <a href="http://www.dzone.com/links/add.html?url=#{postToTools.encodeLink(post)}&title=#{postToTools.encodeTitleForDelicious(post)}">
+ Post to DZone</a>  
+ </s:fragment>
+ <s:fragment rendered="#{showPostTo and post.feed.showDelicious}">
+ <img src="http://images.del.icio.us/static/img/delicious.small.gif" alt="" />
+ <a href="http://del.icio.us/post?v=4&url=#{postToTools.encodeLink(post)}&title=#{postToTools.encodeTitleForDelicious(post)}">
+ Post to del.icio.us</a>  
+ </s:fragment>
+ <s:fragment rendered="#{showPostTo and post.feed.showDigg}">
+ <img src="http://digg.com/img/badges/10x10-digg-thumb.png" alt="" />
+ <a href="http://digg.com/submit?url=#{postToTools.encodeLink(post)}&title=#{postToTools.encodeTitleForDigg(post)}&bodytext=#{postToTools.encodeBodyForDigg(post)}&media=news&topic=programming">
+ Digg this!</a>  
+ </s:fragment>
+ <s:fragment rendered="#{showPostTo and post.feed.showStumble}">
+ <img border="0" src="http://cdn.stumble-upon.com/images/16x16_su_3d.gif" width="10" height="10" alt="" />
+ <a href="http://www.stumbleupon.com/submit?url=#{postToTools.encodeLink(post)}&title=#{postToTools.encodeTitleForDelicious(post)}">
+ Stumble It!</a>
+ </s:fragment>
+
+ <hr />
+</ui:composition>
\ No newline at end of file
Added: feeds100P26/view/emails/new_proposition_email.xhtml
===================================================================
--- feeds100P26/view/emails/new_proposition_email.xhtml (rev 0)
+++ feeds100P26/view/emails/new_proposition_email.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<m:message xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:m="http://jboss.com/products/seam/mail"
+ xmlns:h="http://java.sun.com/jsf/html"
+ charset="UTF-8">
+
+ <m:from name="JBoss.ORG Feeds robot" address="feeds-robot at jboss.org" />
+ <m:to>#{propositionsListener.currentEmail}</m:to>
+ <m:subject>A new feed has been proposed</m:subject>
+
+ <m:body type="plain">
+ A new feed has been proposed:<br />
+ <br />
+ Title: #{feedMod.feed.title}<br />
+ Link: #{feedMod.feed.remoteLink}<br />
+ <br />
+ Visit #{linkService.serverAddress}/#{linkService.contextName}/manage/proposition/proposition_list.seam to accept/reject the feed.<br />
+ <br />
+ -- <br />
+ JBoss.ORG Feeds robot
+ </m:body>
+</m:message>
\ No newline at end of file
Added: feeds100P26/view/emails/proposition_accepted.xhtml
===================================================================
--- feeds100P26/view/emails/proposition_accepted.xhtml (rev 0)
+++ feeds100P26/view/emails/proposition_accepted.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<m:message xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:m="http://jboss.com/products/seam/mail"
+ xmlns:h="http://java.sun.com/jsf/html"
+ charset="UTF-8">
+
+ <m:from name="JBoss.ORG Feeds robot" address="feeds-robot at jboss.org" />
+ <m:to>#{propositionsListener.currentEmail}</m:to>
+ <m:subject>Your feed has been accepted!</m:subject>
+
+ <m:body type="plain">
+ Welcome!<br />
+ <br />
+ Congratulations! Your feed: '#{feedMod.feed.title}' has been accepted and will now be aggregated on
+ JBoss.ORG Feeds.<br />
+ <br />
+ To view the feed, enter:<br />
+ #{linkService.generateFeedPageLink(feedMod.feed)}<br />
+ <br />
+ And don't forget to visit http://labs.jboss.com often!<br />
+ <br />
+ -- <br />
+ JBoss.ORG Feeds robot
+ </m:body>
+</m:message>
\ No newline at end of file
Added: feeds100P26/view/emails/proposition_rejected.xhtml
===================================================================
--- feeds100P26/view/emails/proposition_rejected.xhtml (rev 0)
+++ feeds100P26/view/emails/proposition_rejected.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<m:message xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:m="http://jboss.com/products/seam/mail"
+ xmlns:h="http://java.sun.com/jsf/html"
+ charset="UTF-8">
+
+ <m:from name="JBoss.ORG Feeds robot" address="feeds-robot at jboss.org" />
+ <m:to>#{propositionsListener.currentEmail}</m:to>
+ <m:subject>Your feed has been rejected</m:subject>
+
+ <m:body type="plain">
+ Unfortunately, your feed '#{feedMod.feed.title}' has been rejected.<br />
+ <br />
+ Is it a blog on a JBoss-related subject?<br />
+ Did you submit a feed containing only JBoss-related posts?<br />
+ <br />
+ If so, and you still think that your feed should be aggregated, please contact the project to which's group you
+ submitted your blog.
+ <br />
+ -- <br />
+ JBoss.ORG Feeds robot
+ </m:body>
+</m:message>
\ No newline at end of file
Added: feeds100P26/view/emails/test_email.xhtml
===================================================================
--- feeds100P26/view/emails/test_email.xhtml (rev 0)
+++ feeds100P26/view/emails/test_email.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<m:message xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:m="http://jboss.com/products/seam/mail"
+ xmlns:h="http://java.sun.com/jsf/html"
+ charset="UTF-8">
+
+ <m:from name="JBoss.ORG Feeds robot" address="feeds-robot at jboss.org" />
+ <m:to>#{configurationManager.configuration.adminEmail}</m:to>
+ <m:subject>JBoss Labs Feeds test e-mail</m:subject>
+
+ <m:body type="plain">
+ This is a test e-mail from JBoss Labs Feeds.<br />
+ <br />
+ -- <br />
+ JBoss.ORG Feeds robot
+ </m:body>
+</m:message>
\ No newline at end of file
Added: feeds100P26/view/error/error.xhtml
===================================================================
--- feeds100P26/view/error/error.xhtml (rev 0)
+++ feeds100P26/view/error/error.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,16 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ template="../layout/template.xhtml">
+ <ui:define name="header">
+ Error
+ </ui:define>
+
+ <ui:define name="body">
+ <p>Something bad happened :-(</p>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/error/feed_error.xhtml
===================================================================
--- feeds100P26/view/error/feed_error.xhtml (rev 0)
+++ feeds100P26/view/error/feed_error.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,15 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ template="../layout/template.xhtml">
+ <ui:define name="header">
+ Feed not found
+ </ui:define>
+
+ <ui:define name="body">
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/error/post_error.xhtml
===================================================================
--- feeds100P26/view/error/post_error.xhtml (rev 0)
+++ feeds100P26/view/error/post_error.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,15 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ template="../layout/template.xhtml">
+ <ui:define name="header">
+ Post not found
+ </ui:define>
+
+ <ui:define name="body">
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/home.xhtml
===================================================================
--- feeds100P26/view/home.xhtml (rev 0)
+++ feeds100P26/view/home.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,88 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:mamut="http://mamut.net.pl/jsf"
+ template="layout/template.xhtml">
+ <ui:define name="header">
+ JBoss.ORG Feeds home
+ </ui:define>
+
+ <ui:define name="body">
+ <div id="columnrightBLOG">
+ <div id="TwoColumnBlogJelly">
+ <s:link value="" view="/manage/remote/remote_propose.xhtml" propagation="none">
+ <img src="/feeds/images/propose_blog.png"
+ alt="Propose a Blog! If you are blogging on a JBoss-related subject, aggregate it in our system!" />
+ </s:link>
+ </div>
+
+ <div class="TwoColumnBlogSubnav">
+ <dt>Recent Posts</dt>
+ <!-- TODO: configure the number of posts -->
+ <ui:repeat var="post" value="#{feedsService.getPosts(0, 10)}">
+ <dd>
+ <s:link view="/view/post.xhtml" value="#{post.title}" propagation="none">
+ <f:param name="post" value="#{post.titleAsId}"/>
+ </s:link>
+ </dd>
+ </ui:repeat>
+ </div>
+ </div>
+
+ <div id="columnleftBLOG">
+ <ui:repeat var="group" value="#{groupsService.allGroups}">
+ <mamut:let var="acceptedFeeds" value="#{groupsService.acceptedFeeds(group)}">
+ <s:fragment rendered="#{acceptedFeeds.size() > 0}">
+ <h4>#{group.displayName}</h4>
+ <table cellspacing="5" class="laundrytable" width="75%">
+ <tr>
+ <th width="200px">Feed Author</th>
+ <th width="480px">Feed Title</th>
+ </tr>
+ <ui:repeat var="feed" value="#{acceptedFeeds}">
+ <tr>
+ <td>#{feed.author}</td>
+ <td>
+ <s:link view="/view/feed.xhtml" value="#{feed.title}" propagation="none">
+ <f:param name="name" value="#{feed.name}"/>
+ </s:link>
+ </td>
+ </tr>
+ </ui:repeat>
+ </table>
+ </s:fragment>
+ </mamut:let>
+
+ <s:fragment rendered="#{identity.loggedIn}">
+ <mamut:let var="restrictedFeeds"
+ value="#{feedsSecurity.filterViewableFeeds(groupsService.restrictedFeeds(group))}">
+ <s:fragment rendered="#{restrictedFeeds.size() > 0}">
+ <h4>#{group.displayName} (restricted)</h4>
+ <table cellspacing="5" class="laundrytable" width="75%">
+ <tr>
+ <th width="200px">Feed Author</th>
+ <th width="480px">Feed Title</th>
+ </tr>
+ <ui:repeat var="feed" value="#{restrictedFeeds}">
+ <tr>
+ <td>#{feed.author}</td>
+ <td>
+ <s:link view="/view/feed.xhtml" value="#{feed.title}" propagation="none">
+ <f:param name="name" value="#{feed.name}"/>
+ </s:link>
+ </td>
+ </tr>
+ </ui:repeat>
+ </table>
+ </s:fragment>
+ </mamut:let>
+ </s:fragment>
+ </ui:repeat>
+ </div>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/images/hdr_feed_gradient.gif
===================================================================
(Binary files differ)
Property changes on: feeds100P26/view/images/hdr_feed_gradient.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/view/images/ico_linkarrow_blue.gif
===================================================================
(Binary files differ)
Property changes on: feeds100P26/view/images/ico_linkarrow_blue.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/view/images/portlethdr_home.gif
===================================================================
(Binary files differ)
Property changes on: feeds100P26/view/images/portlethdr_home.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/view/images/propose_blog.png
===================================================================
(Binary files differ)
Property changes on: feeds100P26/view/images/propose_blog.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/view/images/propose_blog_full.png
===================================================================
(Binary files differ)
Property changes on: feeds100P26/view/images/propose_blog_full.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/view/images/wait.gif
===================================================================
(Binary files differ)
Property changes on: feeds100P26/view/images/wait.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: feeds100P26/view/index.html
===================================================================
--- feeds100P26/view/index.html (rev 0)
+++ feeds100P26/view/index.html 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1 @@
+<html />
\ No newline at end of file
Added: feeds100P26/view/layout/menu.xhtml
===================================================================
--- feeds100P26/view/layout/menu.xhtml (rev 0)
+++ feeds100P26/view/layout/menu.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,60 @@
+<div id="ORGheader"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:rich="http://richfaces.org/rich">
+ <div id="ORGLogo">
+ <a href="/">
+ <img src="http://labs.jboss.com/file-access/default/theme/images/common/jbossorg_logo.gif"
+ alt="JBoss.org home" width="250" height="65" border="0"/>
+ </a>
+ </div>
+
+ <div id='utilitynav'>
+ <h:form styleClass="nomargin" id="TopSearch">
+ <ul>
+ <li>
+ <s:fragment rendered="#{!identity.loggedIn}">
+ <s:link view="/security/login.xhtml" value="Login" />  |  
+ </s:fragment>
+ <s:fragment rendered="#{identity.loggedIn}">
+ #{identity.username}   |  
+ <s:link action="#{identity.logout}" value="Logout" />  |  
+ </s:fragment>
+ </li>
+ <li><a href="https://www.redhat.com/apps/store/jboss/">Subscribe</a>  |  </li>
+ <li><a href="http://www.jboss.com/index.html?op=checkage&module=user">Register</a>  |  </li>
+ <li>
+ Search:
+ <h:inputText style="border: 1px solid #6e6e6e; font: 10px Verdana, Helvetica, Arial, sans-serif; padding-left: 2px; margin-left: 10px;"
+ value="#{postSearch.query}" />
+ <h:commandButton value="Search" action="/search/search.xhtml"
+ image="http://labs.jboss.com/file-access/default/theme/images/common/ico_searcharrow.gif"
+ style="width:13px; height:13px">
+ <s:conversationPropagation value="none" />
+ </h:commandButton>
+ </li>
+ </ul>
+ </h:form>
+ </div>
+
+ <!-- Primary Navigation -->
+ <div id="primarynav">
+ <ul>
+ <li>
+ <a href="/">Home</a>
+ </li>
+ <li>
+ <a href="/resources">Resources</a>
+ </li>
+ <li>
+ <a href="/projects">Projects</a>
+ </li>
+ <li id='current'>
+ <a href="/community">Community</a>
+ </li>
+ </ul>
+ </div>
+</div>
Added: feeds100P26/view/layout/template.xhtml
===================================================================
--- feeds100P26/view/layout/template.xhtml (rev 0)
+++ feeds100P26/view/layout/template.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,78 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:mamut="http://mamut.net.pl/jsf"
+ xmlns:a="http://richfaces.org/a4j">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <title>JBoss.ORG Feeds</title>
+ <link href="/feeds/stylesheet/org_main.css" rel="stylesheet" type="text/css" />
+ <link href="/feeds/stylesheet/org_layout.css" rel="stylesheet" type="text/css" />
+ <link href="/feeds/stylesheet/blog.css" rel="stylesheet" type="text/css" />
+ <ui:insert name="additional_headers" />
+</head>
+
+<body>
+<div id="container">
+ <ui:include src="menu.xhtml" />
+
+ <div id="contentcontainer">
+ <div id="ORGContent">
+ <div id='orgprojectdetailstriple'>
+ <mamut:let var="canViewManagement" value="#{identity.hasPermission('management', 'view')}">
+ <s:fragment rendered="#{canViewManagement}">
+ <div class="adminlinks">
+ <s:fragment rendered="#{identity.hasPermission('useraccount', 'view')}">
+ <s:link view="/security/account.xhtml" value="User account" propagation="none" />   
+ </s:fragment>
+ <s:link view="/home.xhtml" value="Feeds home" propagation="none" />   
+ <s:link view="/manage/index.xhtml" value="Manage home" propagation="none" />
+ </div>
+ </s:fragment>
+ <s:fragment rendered="#{identity.hasPermission('useraccount', 'view') and !canViewManagement}">
+ <div class="adminlinks">
+ <s:link view="/security/account.xhtml" value="User account" propagation="none" />
+ </div>
+ </s:fragment>
+ </mamut:let>
+
+ <h3 id="majorsectiontitle" style="margin-bottom: 0"><ui:insert name="header"/></h3>
+ </div>
+ <div id="orghomemaximized">
+ <div>
+ <h:messages globalOnly="true"
+ infoClass="messages_info"
+ warnClass="messages_warn"
+ errorClass="messages_warn"
+ fatalClass="messages_warn"
+ styleClass="messages"
+ />
+ </div>
+
+ <ui:insert name="body"/>
+ </div>
+ </div>
+
+ <div class="footer">
+ <p>
+ <a href="http://www.redhat.com/">Red Hat.com</a> |
+ <a href="http://www.jboss.com/">JBoss.com</a> |
+ <a href="http://www.jboss.com/company/contact">Contact Us</a> |
+ <a href="http://www.redhat.com/about/careers">Careers</a>
+ </p>
+ <p>
+ Hosted on <a href="http://labs.jboss.com/jbosslabs">JBoss Labs</a>.
+ Powered by <a href="http://labs.jboss.com/jbossas">JBoss AS</a>,
+ <a href="http://labs.jboss.com/jbossportal">JBoss Portal</a>,
+ <a href="http://labs.jboss.com/drools">Drools</a>and
+ <a href="http://labs.jboss.com/jbossseam">JBoss Seam</a>.
+ </p>
+ </div>
+ </div>
+</div>
+</body>
+</html>
Added: feeds100P26/view/manage/aggregated/aggregated_add.xhtml
===================================================================
--- feeds100P26/view/manage/aggregated/aggregated_add.xhtml (rev 0)
+++ feeds100P26/view/manage/aggregated/aggregated_add.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,20 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../../layout/template.xhtml">
+ <ui:define name="header">
+ Add aggregated feed
+ </ui:define>
+
+ <ui:define name="body">
+ <ui:include src="aggregated_mod.xhtml">
+ <ui:param name="new" value="true" />
+ </ui:include>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/aggregated/aggregated_edit.xhtml
===================================================================
--- feeds100P26/view/manage/aggregated/aggregated_edit.xhtml (rev 0)
+++ feeds100P26/view/manage/aggregated/aggregated_edit.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,19 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../../layout/template.xhtml">
+ <ui:define name="header">
+ Edit aggregated feed: #{feedMod.feed.name}
+ </ui:define>
+
+ <ui:define name="body"><ui:include src="aggregated_mod.xhtml">
+ <ui:param name="new" value="false" />
+ </ui:include>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/aggregated/aggregated_mod.xhtml
===================================================================
--- feeds100P26/view/manage/aggregated/aggregated_mod.xhtml (rev 0)
+++ feeds100P26/view/manage/aggregated/aggregated_mod.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,140 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j">
+<div class="TwoColumnBlogSubnav">
+ <h4>Tips</h4>
+ <ul>
+ <li>
+ If you choose to aggregate a feed group, all feeds from that group will be aggregated.
+ </li>
+ <li class="last">
+ Filters will be applied to each post in a feed, group, or to all posts (depending where you choose to
+ place the filter), and if the filter output is positive the post will be included in the aggregated
+ feed.
+ </li>
+ </ul>
+</div>
+
+<h:form>
+<div class="adminforms">
+<h4>Feeds to include:</h4>
+
+<h:panelGroup>
+ <h:dataTable value="#{aggregatedFeedMod.availableFeeds}" var="feed" id="availableFeedsTable"
+ styleClass="basetablestyle" headerClass="header tableheader" rowClasses="oddRow,evenRow"
+ cellspacing="0" cellpadding="4">
+ <h:column>
+ <h:selectBooleanCheckbox value="#{aggregatedFeedMod.selectedFeeds[feed]}" styleClass="radios">
+ <a:support event="onclick" reRender="availableFeedsTable" />
+ </h:selectBooleanCheckbox>
+ </h:column>
+ <h:column>
+ <f:facet name="header">
+ Feed name:
+ </f:facet>
+ #{feed.name}
+ </h:column>
+ <h:column>
+ <f:facet name="header">
+ Local filters, applied only to this feed:
+ </f:facet>
+ <h:panelGroup rendered="#{aggregatedFeedMod.selectedFeeds[feed]}">
+ <ul>
+ <ui:repeat var="filter" value="#{aggregatedFeedMod.selectedFeedsFilters[feed]}">
+ <li>
+ #{filter}
+ (<h:commandLink action="#{aggregatedFeedMod.removeFilter(aggregatedFeedMod.selectedFeedsFilters[feed],filter)}"
+ value="Remove" />)
+ </li>
+ </ui:repeat>
+ </ul>
+
+ <h:commandLink action="#{filterAdd.addToList(aggregatedFeedMod.selectedFeedsFilters[feed])}"
+ value="Add filter" />
+ </h:panelGroup>
+ </h:column>
+ </h:dataTable>
+</h:panelGroup>
+
+<h4>Feed groups to include:</h4>
+
+<h:panelGroup>
+ <h:dataTable value="#{aggregatedFeedMod.availableGroups}" var="group" id="availableGroupsTable"
+ styleClass="basetablestyle" headerClass="header tableheader" rowClasses="oddRow,evenRow"
+ cellspacing="0" cellpadding="4">
+ <h:column>
+ <h:selectBooleanCheckbox value="#{aggregatedFeedMod.selectedGroups[group]}" styleClass="radios">
+ <a:support event="onclick" reRender="availableGroupsTable" />
+ </h:selectBooleanCheckbox>
+ </h:column>
+ <h:column>
+ <f:facet name="header">
+ Group name:
+ </f:facet>
+ #{group.displayName}
+ </h:column>
+ <h:column>
+ <f:facet name="header">
+ Local filters, applied only to this group:
+ </f:facet>
+ <h:panelGroup rendered="#{aggregatedFeedMod.selectedGroups[group]}">
+ <ul>
+ <ui:repeat var="filter" value="#{aggregatedFeedMod.selectedGroupsFilters[group]}">
+ <li>
+ #{filter}
+ (<h:commandLink action="#{aggregatedFeedMod.removeFilter(aggregatedFeedMod.selectedGroupsFilters[group],filter)}"
+ value="Remove" />)
+ </li>
+ </ui:repeat>
+ </ul>
+
+ <h:commandLink action="#{filterAdd.addToList(aggregatedFeedMod.selectedGroupsFilters[group])}"
+ value="Add filter" />
+ </h:panelGroup>
+ </h:column>
+ </h:dataTable>
+</h:panelGroup>
+
+<h4>Global filters, applied to all feeds:</h4>
+
+<ul>
+ <ui:repeat var="filter" value="#{aggregatedFeedMod.globalFilters}">
+ <li>
+ #{filter}
+ (<h:commandLink action="#{aggregatedFeedMod.removeFilter(aggregatedFeedMod.globalFilters,filter)}"
+ value="Remove" />)
+ </li>
+ </ui:repeat>
+</ul>
+
+<h:commandLink action="#{filterAdd.addToList(aggregatedFeedMod.globalFilters)}" value="Add filter" />
+
+<div id="proceed" class="formbuttons">
+ <ul>
+ <s:fragment rendered="#{new}">
+ <li>
+ <h:commandButton value="Next »" action="#{aggregatedFeedMod.saveNew}" styleClass="submit" />
+ </li>
+ </s:fragment>
+ <s:fragment rendered="#{!new}">
+ <li>
+ <h:commandButton value="Save" action="#{aggregatedFeedMod.saveExisting}" styleClass="submit" />
+ </li>
+ </s:fragment>
+ <li>
+ <s:button value="Cancel" view="/manage/index.xhtml" propagation="end" styleClass="submit" />
+ </li>
+ <li>
+ <ui:include src="../../common/ajax_status.xhtml" />
+ </li>
+ </ul>
+</div>
+</div>
+</h:form>
+</ui:composition>
Added: feeds100P26/view/manage/aggregated/filter_add.xhtml
===================================================================
--- feeds100P26/view/manage/aggregated/filter_add.xhtml (rev 0)
+++ feeds100P26/view/manage/aggregated/filter_add.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,111 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../../layout/template.xhtml">
+<ui:define name="header">
+ Add a filter feed
+</ui:define>
+
+<ui:define name="body">
+ <div class="TwoColumnBlogSubnav">
+ <h4>Tips</h4>
+ <ul>
+ <li>
+ An <a href="http://www.regular-expressions.info/javascriptexample.html" target="_blank">online regular
+ expressions tester</a> in case you need help.
+ </li>
+ </ul>
+ </div>
+
+ <div class="adminforms">
+ <table class="basetablestyle" cellspacing="0" cellpadding="4">
+ <tr>
+ <th class="header tableHeader">Filter function</th>
+ <th class="header tableHeader">Configure/add</th>
+ </tr>
+ <tr class="oddRow">
+ <td>Only entries with enclosures filter (podcast):</td>
+ <td>
+ <h:form>
+ <h:commandButton value="Add" action="#{filterAdd.add(filterAdd.podcastFilter)}"
+ styleClass="submit" />
+ </h:form>
+ </td>
+ </tr>
+ <tr class="evenRow">
+ <td>Only entries without enclosure filter (not-podcast):</td>
+ <td>
+ <h:form>
+ <h:commandButton value="Add" action="#{filterAdd.add(filterAdd.notPodcastFilter)}"
+ styleClass="submit" />
+ </h:form>
+ </td>
+ </tr>
+ <tr class="oddRow">
+ <td>Only entries whose author matches a regular expression:</td>
+ <td>
+ <h:form>
+ <h:outputLabel for="author">
+ <span class="required">*</span> Regular expression:
+ </h:outputLabel>
+ <br />
+ <h:panelGroup>
+ <h:inputText id="author" value="#{filterAdd.authorRegexpFilter.regexp}" required="true" size="16">
+ <a:support event="onblur" reRender="authorMessage" ajaxSingle="true" bypassUpdates="true"/>
+ <s:validate />
+ </h:inputText>
+
+ <a:outputPanel id="authorMessage">
+ <h:message for="author" styleClass="error" />
+ </a:outputPanel>
+ </h:panelGroup>
+ <br />
+ <h:commandButton value="Add" action="#{filterAdd.add(filterAdd.authorRegexpFilter)}"
+ styleClass="submit" />
+ </h:form>
+ </td>
+ </tr>
+ <tr class="evenRow">
+ <td>Only entries where at least one category matches a regular expression:</td>
+ <td>
+ <h:form>
+ <h:outputLabel for="category">
+ <span class="required">*</span> Regular expression:
+ </h:outputLabel>
+ <br />
+ <h:panelGroup>
+ <h:inputText id="category" value="#{filterAdd.categoryRegexpFilter.regexp}" required="true" size="16">
+ <a:support event="onblur" reRender="categoryMessage" ajaxSingle="true" bypassUpdates="true"/>
+ <s:validate />
+ </h:inputText>
+
+ <a:outputPanel id="categoryMessage">
+ <h:message for="category" styleClass="error" />
+ </a:outputPanel>
+ </h:panelGroup>
+ <br />
+ <h:commandButton value="Add" action="#{filterAdd.add(filterAdd.categoryRegexpFilter)}"
+ styleClass="submit" />
+ </h:form>
+ </td>
+ </tr>
+ </table>
+
+ <h:form>
+ <div id="proceed" class="formbuttons">
+ <ul>
+ <li>
+ <h:commandButton value="Cancel" action="#{filterAdd.cancel}" styleClass="submit"/>
+ </li>
+ </ul>
+ </div>
+ </h:form>
+ </div>
+</ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/configuration_manager.xhtml
===================================================================
--- feeds100P26/view/manage/configuration_manager.xhtml (rev 0)
+++ feeds100P26/view/manage/configuration_manager.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,42 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../layout/template.xhtml">
+ <ui:define name="header">
+ Configuration manager
+ </ui:define>
+ <ui:define name="body">
+ <h:form>
+ <div class="adminforms">
+ <h:panelGrid columns="2">
+ <h:outputLabel for="adminEmail">Administrator email:</h:outputLabel>
+ <h:panelGroup>
+ <h:inputText id="adminEmail" value="#{configurationManager.configuration.adminEmail}" size="16">
+ <a:support event="onblur" reRender="adminEmailMessage" ajaxSingle="true" bypassUpdates="true"/>
+ <s:validate />
+ </h:inputText>
+ <a:outputPanel id="adminEmailMessage">
+ <h:message for="adminEmail" styleClass="error" />
+ </a:outputPanel>
+ </h:panelGroup>
+ </h:panelGrid>
+ <div class="formbuttons">
+ <ul>
+ <li>
+ <h:commandButton value="Save changes" action="#{configurationManager.save}" styleClass="submit" />
+ </li>
+ <li>
+ <h:commandButton value="Save and test email" action="#{configurationManager.testEmail}" styleClass="submit" />
+ </li>
+ </ul>
+ </div>
+ </div>
+ </h:form>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/feed_add.xhtml
===================================================================
--- feeds100P26/view/manage/feed_add.xhtml (rev 0)
+++ feeds100P26/view/manage/feed_add.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,21 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../layout/template.xhtml">
+ <ui:define name="header">
+ Add a new feed - edit data
+ </ui:define>
+
+ <ui:define name="body">
+ <ui:include src="feed_mod.xhtml">
+ <ui:param name="new" value="true" />
+ <ui:param name="advanced" value="true" />
+ </ui:include>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/feed_edit.xhtml
===================================================================
--- feeds100P26/view/manage/feed_edit.xhtml (rev 0)
+++ feeds100P26/view/manage/feed_edit.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,21 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../layout/template.xhtml">
+ <ui:define name="header">
+ Edit feed: #{feedMod.feed.name}
+ </ui:define>
+
+ <ui:define name="body">
+ <ui:include src="feed_mod.xhtml">
+ <ui:param name="new" value="false" />
+ <ui:param name="advanced" value="true" />
+ </ui:include>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/feed_mod.xhtml
===================================================================
--- feeds100P26/view/manage/feed_mod.xhtml (rev 0)
+++ feeds100P26/view/manage/feed_mod.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,199 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:blog="http://jboss.org/blog/tags"
+ xmlns:a="http://richfaces.org/a4j">
+<div class="TwoColumnBlogSubnav">
+ <h4>Tips</h4>
+ <ul>
+ <li class="last">
+ Please fill in all the details that are necessary to handle your feed.
+ </li>
+ </ul>
+</div>
+
+<h:form>
+<div class="adminforms">
+<h:panelGrid columns="2">
+<h:outputLabel for="name"><span class="required">*</span> Name (to use in URLs):</h:outputLabel>
+<h:panelGroup>
+ <h:inputText id="name" value="#{feedMod.feed.name}" required="true" size="16">
+ <blog:uniqueFeedNameValidator entityId="#{feedMod.feed.id}" />
+ <a:support event="onblur" reRender="nameMessage" ajaxSingle="true" bypassUpdates="true"/>
+ <s:validate />
+ </h:inputText>
+ <a:outputPanel id="nameMessage">
+ <h:message for="name" styleClass="error" />
+ </a:outputPanel>
+</h:panelGroup>
+
+<h:outputLabel for="title"><span class="required">*</span> Title:</h:outputLabel>
+<h:panelGroup>
+ <h:inputText id="title" value="#{feedMod.feed.title}" required="true" size="32">
+ <a:support event="onblur" reRender="titleMessage" ajaxSingle="true" bypassUpdates="true"/>
+ <s:validate />
+ </h:inputText>
+
+ <a:outputPanel id="titleMessage">
+ <h:message for="title" styleClass="error" />
+ </a:outputPanel>
+</h:panelGroup>
+
+<h:outputLabel for="author"><span class="required">*</span> Author:</h:outputLabel>
+<h:panelGroup>
+ <h:inputText id="author" value="#{feedMod.feed.author}" required="true" size="32">
+ <a:support event="onblur" reRender="authorMessage" ajaxSingle="true" bypassUpdates="true"/>
+ <s:validate />
+ </h:inputText>
+
+ <a:outputPanel id="authorMessage">
+ <h:message for="author" styleClass="error" />
+ </a:outputPanel>
+</h:panelGroup>
+
+<!--<h:outputLabel for="description">Description:</h:outputLabel>
+<h:panelGroup>
+ <h:inputTextarea id="description" value="#{feedMod.feed.description}" rows="4" cols="32">
+ <a:support event="onblur" reRender="descriptionMessage" ajaxSingle="true" bypassUpdates="true"/>
+ <s:validate />
+ </h:inputTextarea>
+
+ <a:outputPanel id="descriptionMessage">
+ <h:message for="description" styleClass="error" />
+ </a:outputPanel>
+</h:panelGroup>-->
+
+<h:outputLabel for="link" rendered="#{not (feedMod.feed.link == null)}">Link to blog:</h:outputLabel>
+<h:panelGroup rendered="#{not (feedMod.feed.link == null)}">
+ <h:inputText id="link" value="#{feedMod.feed.link}" size="48" maxlength="64" disabled="true">
+ <s:validate />
+ </h:inputText>
+</h:panelGroup>
+
+<h:outputLabel for="group"><span class="required">*</span> Project/ group:</h:outputLabel>
+<h:panelGroup>
+ <h:selectOneMenu id="group" required="true" value="#{feedMod.feed.group}">
+ <a:support event="onblur" reRender="groupMessage" ajaxSingle="true" bypassUpdates="true"/>
+ <s:convertEntity />
+ <s:selectItems var="group" value="#{groupsSecurity.filterForFeedMod(feedMod.feed, groupsService.allGroups, new)}"
+ label="#{group.displayName}" />
+ </h:selectOneMenu>
+
+ <a:outputPanel id="groupMessage">
+ <h:message for="group" styleClass="error" />
+ </a:outputPanel>
+
+ <s:div rendered="#{identity.hasPermission('group', 'add')}">
+ <s:link value="Add new group" action="#{groupMod.add}" /><br />
+ </s:div>
+</h:panelGroup>
+
+<h:outputLabel for="maxPostsInFeed">
+ <span class="required">*</span> Maximum number of posts in an atom feed:
+</h:outputLabel>
+<h:panelGroup>
+ <h:inputText id="maxPostsInFeed" value="#{feedMod.feed.maxPostsInFeed}" required="true" size="16">
+ <a:support event="onblur" reRender="maxPostsInFeedMessage" ajaxSingle="true" bypassUpdates="true"/>
+ <s:validate />
+ </h:inputText>
+
+ <a:outputPanel id="maxPostsInFeedMessage">
+ <h:message for="maxPostsInFeed" styleClass="error" />
+ </a:outputPanel>
+</h:panelGroup>
+
+<h:outputLabel for="maxPostsOnPage">
+ <span class="required">*</span> Maximum number of posts to display on one page:
+</h:outputLabel>
+<h:panelGroup>
+ <h:inputText id="maxPostsOnPage" value="#{feedMod.feed.maxPostsOnPage}" required="true" size="16">
+ <a:support event="onblur" reRender="maxPostsOnPageMessage" ajaxSingle="true" bypassUpdates="true"/>
+ <s:validate />
+ </h:inputText>
+
+ <a:outputPanel id="maxPostsOnPageMessage">
+ <h:message for="maxPostsOnPage" styleClass="error" />
+ </a:outputPanel>
+</h:panelGroup>
+
+<h:outputLabel for="showDelicious">
+ Add a "Post to del.icio.us" link to every post:
+</h:outputLabel>
+<h:panelGroup>
+ <h:selectBooleanCheckbox id="showDelicious" value="#{feedMod.feed.showDelicious}" />
+</h:panelGroup>
+
+<h:outputLabel for="showDigg">
+ Add a "Digg this!" link to every post:
+</h:outputLabel>
+<h:panelGroup>
+ <h:selectBooleanCheckbox id="showDigg" value="#{feedMod.feed.showDigg}" />
+</h:panelGroup>
+
+<h:outputLabel for="showDzone">
+ Add a "Post to DZone" link to every post:
+</h:outputLabel>
+<h:panelGroup>
+ <h:selectBooleanCheckbox id="showDzone" value="#{feedMod.feed.showDzone}" />
+</h:panelGroup>
+
+<h:outputLabel for="showStumble">
+ Add a "Stumble It!" link to every post:
+</h:outputLabel>
+<h:panelGroup>
+ <h:selectBooleanCheckbox id="showStumble" value="#{feedMod.feed.showStumble}" />
+</h:panelGroup>
+
+<h:outputLabel for="restricted" rendered="#{advanced}">
+ This is a restricted feed, viewable only by authorized users:
+</h:outputLabel>
+<h:panelGroup rendered="#{advanced}">
+ <h:selectBooleanCheckbox id="restricted" value="#{feedMod.feed.restricted}" />
+</h:panelGroup>
+
+<h:outputLabel><span class="required">*</span> Xml templates:</h:outputLabel>
+<h:panelGroup>
+ <h:dataTable var="templateType" value="#{feedMod.templateTypes}">
+ <h:column>
+ #{templateType}:
+ </h:column>
+ <h:column>
+ <h:selectOneMenu value="#{feedMod.feed.templates[templateType]}">
+ <s:convertEntity />
+ <s:selectItems var="template" value="#{templateService.templatesOfType(templateType)}"
+ label="#{template.name}" />
+ </h:selectOneMenu>
+ </h:column>
+ </h:dataTable>
+</h:panelGroup>
+
+</h:panelGrid>
+
+<div class="formbuttons">
+ <ul>
+ <s:fragment rendered="#{new}">
+ <li>
+ <h:commandButton value="Add" action="#{feedMod.saveNew}" rendered="#{new}" styleClass="submit" />
+ </li>
+ </s:fragment>
+ <s:fragment rendered="#{!new}">
+ <li>
+ <h:commandButton value="Save" action="#{feedMod.saveExisting}" rendered="#{!new}" styleClass="submit" />
+ </li>
+ </s:fragment>
+ <li>
+ <s:button value="Cancel" view="/manage/index.xhtml" propagation="end" styleClass="submit"
+ rendered="#{identity.hasPermission('management', 'view')}"/>
+ <s:button value="Cancel" view="/home.xhtml" propagation="end" styleClass="submit"
+ rendered="#{!identity.hasPermission('management', 'view')}"/>
+ </li>
+ </ul>
+</div>
+</div>
+</h:form>
+</ui:composition>
Added: feeds100P26/view/manage/feed_propose.xhtml
===================================================================
--- feeds100P26/view/manage/feed_propose.xhtml (rev 0)
+++ feeds100P26/view/manage/feed_propose.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,21 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../layout/template.xhtml">
+ <ui:define name="header">
+ Propose a new feed - edit data
+ </ui:define>
+
+ <ui:define name="body">
+ <ui:include src="feed_mod.xhtml">
+ <ui:param name="new" value="true" />
+ <ui:param name="advanced" value="false" />
+ </ui:include>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/group/group_add.xhtml
===================================================================
--- feeds100P26/view/manage/group/group_add.xhtml (rev 0)
+++ feeds100P26/view/manage/group/group_add.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,20 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../../layout/template.xhtml">
+ <ui:define name="header">
+ Add feed group
+ </ui:define>
+
+ <ui:define name="body">
+ <ui:include src="group_mod.xhtml">
+ <ui:param name="new" value="true" />
+ </ui:include>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/group/group_edit.xhtml
===================================================================
--- feeds100P26/view/manage/group/group_edit.xhtml (rev 0)
+++ feeds100P26/view/manage/group/group_edit.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,20 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../../layout/template.xhtml">
+ <ui:define name="header">
+ Edit feed group: #{groupMod.group.displayName}
+ </ui:define>
+
+ <ui:define name="body">
+ <ui:include src="group_mod.xhtml">
+ <ui:param name="new" value="false" />
+ </ui:include>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/group/group_list.xhtml
===================================================================
--- feeds100P26/view/manage/group/group_list.xhtml (rev 0)
+++ feeds100P26/view/manage/group/group_list.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,56 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../../layout/template.xhtml">
+ <ui:define name="header">
+ Manage groups
+ </ui:define>
+
+ <ui:define name="body">
+ <div class="adminlist">
+ <dl>
+ <dd><s:link value="Add new group" action="#{groupMod.add}" /></dd>
+ <dt>Current groups:</dt>
+ <hr />
+ </dl>
+ </div>
+
+ <table border="0" cellpadding="4" cellspacing="0" class="basetablestyle" style="margin-top:12px;">
+ <tr class="header">
+ <td class="tableheaderfirst" style="width:160px;">Group display name</td>
+ <td class="tableheader">Group name</td>
+ <td class="tableheader" />
+ <td class="tableheader" />
+ </tr>
+
+ <a:repeat var="group" value="#{groupsService.allGroups}" rowKeyVar="rowNumber">
+ <s:fragment rendered="#{identity.hasPermission('group', 'edit', group) ||
+ identity.hasPermission('group', 'delete', group)}">
+ <tr class="#{(rowNumber%2 == 0) ? 'evenRow' : 'oddRow'}">
+ <td class="rowlinefirst" style="font-weight:bold;">#{group.displayName}</td>
+ <td class="rowline">#{group.name}</td>
+ <td class="rowline">
+ <s:link action="#{groupMod.edit}" value="Edit"
+ rendered="#{identity.hasPermission('group', 'edit', group)}">
+ <f:param name="id" value="#{group.id}" />
+ </s:link>
+ </td>
+ <td class="rowline">
+ <s:link view="/manage/group/group_delete.xhtml" action="#{groupMod.delete}" value="Delete"
+ onclick="if (!confirm('Are you sure you want to delete this group?')) return false"
+ rendered="#{identity.hasPermission('group', 'delete', group)}">
+ <f:param name="id" value="#{group.id}" />
+ </s:link>
+ </td>
+ </tr>
+ </s:fragment>
+ </a:repeat>
+ </table>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/group/group_mod.xhtml
===================================================================
--- feeds100P26/view/manage/group/group_mod.xhtml (rev 0)
+++ feeds100P26/view/manage/group/group_mod.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,110 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:blog="http://jboss.org/blog/tags"
+ xmlns:a="http://richfaces.org/a4j">
+ <div class="TwoColumnBlogSubnav">
+ <h4>Tips</h4>
+ <ul>
+ <li>
+ Notifications of new proposed feeds in this group will be sent to the e-mail
+ specified below (field "Administrator e-mail").
+ </li>
+ <li class="last">
+ Header is an optional piece of HTML that will be displayed on the top of the page when
+ viewing feeds/posts from that group.
+ </li>
+ </ul>
+ </div>
+
+ <div class="adminforms">
+ <h:form>
+ <h:panelGrid columns="2">
+ <h:outputLabel for="name"><span class="required">*</span> Name (to use in URLs):</h:outputLabel>
+ <h:panelGroup>
+ <h:inputText id="name" value="#{groupMod.group.name}" required="true" size="32">
+ <blog:uniqueGroupNameValidator entityId="#{groupMod.group.id}" />
+ <a:support event="onblur" reRender="nameMessage" ajaxSingle="true" bypassUpdates="true"/>
+ <s:validate />
+ </h:inputText>
+
+ <a:outputPanel id="nameMessage">
+ <h:message for="name" styleClass="error" />
+ </a:outputPanel>
+ </h:panelGroup>
+
+ <h:outputLabel for="displayName"><span class="required">*</span> Display name:</h:outputLabel>
+ <h:panelGroup>
+ <h:inputText id="displayName" value="#{groupMod.group.displayName}" required="true" size="32">
+ <a:support event="onblur" reRender="displayNameMessage" ajaxSingle="true" bypassUpdates="true"/>
+ <s:validate />
+ </h:inputText>
+
+ <a:outputPanel id="displayNameMessage">
+ <h:message for="displayName" styleClass="error" />
+ </a:outputPanel>
+ </h:panelGroup>
+
+ <h:outputLabel for="adminEmail">Administrator e-mail:</h:outputLabel>
+ <h:panelGroup>
+ <h:inputText id="adminEmail" value="#{groupMod.group.adminEmail}" size="32">
+ <a:support event="onblur" reRender="adminEmailMessage" ajaxSingle="true" bypassUpdates="true"/>
+ <s:validate />
+ </h:inputText>
+
+ <a:outputPanel id="adminEmailMessage">
+ <h:message for="adminEmail" styleClass="error" />
+ </a:outputPanel>
+ </h:panelGroup>
+
+ <h:outputLabel for="header">Header:</h:outputLabel>
+ <h:panelGroup>
+ <h:inputTextarea id="header" value="#{groupMod.group.header}" rows="25" cols="60">
+ <a:support event="onblur" reRender="headerMessage" ajaxSingle="true" bypassUpdates="true"/>
+ <s:validate />
+ </h:inputTextarea>
+
+ <a:outputPanel id="headerMessage">
+ <h:message for="header" styleClass="error" />
+ </a:outputPanel>
+ </h:panelGroup>
+ </h:panelGrid>
+
+ <div id="proceed" class="formbuttons">
+ <ul>
+ <s:fragment rendered="#{new}">
+ <li>
+ <h:commandButton value="Add" action="#{groupMod.saveNew}" styleClass="submit" />
+ </li>
+ </s:fragment>
+ <s:fragment rendered="#{!new}">
+ <li>
+ <h:commandButton value="Save" action="#{groupMod.saveExisting}" styleClass="submit" />
+ </li>
+ </s:fragment>
+ <li>
+ <a:commandButton value="Update preview" reRender="preview,displayNameMessage,nameMessage"
+ styleClass="submit" />
+ </li>
+ <li>
+ <s:button value="Cancel" action="#{groupMod.cancel}" styleClass="submit" />
+ </li>
+ <li>
+ <ui:include src="../../common/ajax_status.xhtml" />
+ </li>
+ </ul>
+ </div>
+
+ <s:div styleClass="formbuttons" id="preview">
+ Preview of the header: <br />
+
+ <h:outputText value="#{groupMod.group.header}" escape="false" />
+ </s:div>
+ </h:form>
+ </div>
+</ui:composition>
Added: feeds100P26/view/manage/highlights/highlights_edit.xhtml
===================================================================
--- feeds100P26/view/manage/highlights/highlights_edit.xhtml (rev 0)
+++ feeds100P26/view/manage/highlights/highlights_edit.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,18 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../../layout/template.xhtml">
+ <ui:define name="header">
+ Edit highlights feed: #{feedMod.feed.name}
+ </ui:define>
+
+ <ui:define name="body">
+ <ui:include src="highlights_mod.xhtml" />
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/highlights/highlights_mod.xhtml
===================================================================
--- feeds100P26/view/manage/highlights/highlights_mod.xhtml (rev 0)
+++ feeds100P26/view/manage/highlights/highlights_mod.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,71 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j">
+ <div class="adminforms">
+ <h:form>
+ <s:div rendered="#{highlightsFeedMod.highlightsFeed.selectedPosts.size == 0}">
+ There are no posts selected.
+ </s:div>
+
+ <s:div id="postsTable">
+ <table class="basetablestyle" >
+ <a:repeat rowKeyVar="rowNumber" var="post" value="#{highlightsFeedMod.highlightsFeed.selectedPosts}">
+ <tr class="#{(rowNumber%2 == 0) ? 'evenRow' : 'oddRow'}">
+ <td>
+ #{rowNumber}
+ </td>
+ <td>
+ <ui:include src="../../common/post.xhtml">
+ <ui:param name="post" value="#{post}" />
+ <ui:param name="showSummary" value="true" />
+ <ui:param name="showAddToHighlights" value="false" />
+ </ui:include>
+ </td>
+ <td>
+ <a:commandLink value="Move up" action="#{highlightsFeedMod.moveUp(rowNumber)}"
+ reRender="postsTable" rendered="#{rowNumber != 0}" />
+ </td>
+ <td>
+ <a:commandLink value="Move down" action="#{highlightsFeedMod.moveDown(rowNumber)}"
+ reRender="postsTable"
+ rendered="#{rowNumber != highlightsFeedMod.highlightsFeed.selectedPosts.size()-1}"/>
+ </td>
+ <td>
+ <a:commandLink value="Move to position:" action="#{highlightsFeedMod.moveTo(rowNumber)}"
+ reRender="postsTable" />
+ </td>
+ <td>
+ <h:inputText size="2" maxlength="2" value="#{highlightsFeedMod.positions[rowNumber]}" />
+ </td>
+ <td>
+ <a:commandLink value="Delete" action="#{highlightsFeedMod.delete(rowNumber)}"
+ reRender="postsTable" />
+ </td>
+ </tr>
+ </a:repeat>
+ </table>
+ </s:div>
+
+ <s:div styleClass="formbuttons">
+ <ul>
+ <li>
+ <h:commandButton value="Save" action="#{highlightsFeedMod.saveExisting}"
+ styleClass="submit" />
+ </li>
+ <li>
+ <s:button value="Cancel" view="/manage/index.xhtml" propagation="end" styleClass="submit" />
+ </li>
+ <li>
+ <ui:include src="../../common/ajax_status.xhtml" />
+ </li>
+ </ul>
+ </s:div>
+ </h:form>
+ </div>
+</ui:composition>
Added: feeds100P26/view/manage/highlights/post_add.xhtml
===================================================================
--- feeds100P26/view/manage/highlights/post_add.xhtml (rev 0)
+++ feeds100P26/view/manage/highlights/post_add.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,53 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../../layout/template.xhtml">
+ <ui:define name="header">
+ Add post '#{highlightsFeedMod.post.title}' to a highlights feed
+ </ui:define>
+
+ <ui:define name="body">
+ <div class="TwoColumnBlogSubnav">
+ <h4>Tips</h4>
+ <ul>
+ <li id="last">
+ After selecting a highlights feed, you'll be able to change the order of the posts.
+ </li>
+ </ul>
+ </div>
+
+ <div class="adminforms">
+ <h:form>
+ <h:panelGrid columns="2">
+ <h:outputLabel for="feeds">Highlights feed:</h:outputLabel>
+ <h:panelGroup>
+ <h:selectOneListbox id="feeds" value="#{highlightsFeedMod.selectedFeed}" required="true">
+ <s:selectItems var="feed" value="#{highlightsSecurity.feeds}" label="#{feed.title}" />
+ <s:convertEntity />
+ </h:selectOneListbox>
+
+ <a:outputPanel id="feedsMessage">
+ <h:message for="feeds" styleClass="error" />
+ </a:outputPanel>
+ </h:panelGroup>
+ </h:panelGrid>
+ <div id="proceed" class="formbuttons">
+ <ul>
+ <li>
+ <h:commandButton value="Select" action="#{highlightsFeedMod.addPost}" styleClass="submit"/>
+ </li>
+ <li>
+ <s:button value="Cancel" view="/home.xhtml" styleClass="submit"/>
+ </li>
+ </ul>
+ </div>
+ </h:form>
+ </div>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/index.xhtml
===================================================================
--- feeds100P26/view/manage/index.xhtml (rev 0)
+++ feeds100P26/view/manage/index.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,172 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ xmlns:mamut="http://mamut.net.pl/jsf"
+ template="../layout/template.xhtml">
+<ui:define name="header">
+ Manage feeds
+</ui:define>
+<ui:define name="body">
+<div class="TwoColumnBlogSubnav">
+ <h4>Tips</h4>
+ <ul>
+ <li class="last">
+ The <a href="http://labs.jboss.com/files/jbosslabs/feeds_tutorial/tutorial.html">tutorial</a> may be
+ helpful.
+ </li>
+ </ul>
+</div>
+
+<div class="adminlist">
+ <dl>
+ <s:fragment rendered="#{propositionsTools.pendingPropositions > 0 ||
+ identity.hasPermission('feed', 'add_any')}">
+ <dt>New feed operations:</dt>
+ <hr />
+ <s:fragment rendered="#{propositionsTools.pendingPropositions > 0}">
+ <dd>
+ <s:link value="Pending feed propositions (#{propositionsTools.pendingPropositions})"
+ view="/manage/proposition/proposition_list.xhtml" />
+ </dd>
+ </s:fragment>
+ <s:fragment rendered="#{identity.hasPermission('feed', 'add_any')}">
+ <ui:repeat var="feedType" value="#{feedTypes.allTypes}">
+ <dd>
+ <s:link value="Add a new #{feedType.name()} feed" view="#{feedType.addPage()}" />
+ </dd>
+ </ui:repeat>
+ </s:fragment>
+ </s:fragment>
+ <s:fragment rendered="#{identity.hasPermission('management_groups', 'view') ||
+ identity.hasPermission('management_template', 'view') ||
+ identity.hasPermission('management_update', 'view') ||
+ identity.hasPermission('security', 'view')}">
+ <dt>Other operations:</dt>
+ <hr />
+ <s:fragment rendered="#{identity.hasPermission('management_groups', 'view')}">
+ <dd><s:link value="Manage feed groups" view="/manage/group/group_list.xhtml" /></dd>
+ </s:fragment>
+ <s:fragment rendered="#{identity.hasPermission('management_template', 'view')}">
+ <dd><s:link value="Manage feed templates" view="/manage/template/template_list.xhtml" /></dd>
+ </s:fragment>
+ <s:fragment rendered="#{identity.hasPermission('management_update', 'view')}">
+ <dd><s:link value="Manage updates" view="/manage/update_manager.xhtml" /></dd>
+ </s:fragment>
+ <s:fragment rendered="#{identity.hasPermission('management_configuration', 'view')}">
+ <dd><s:link value="Manage configuration" view="/manage/configuration_manager.xhtml" /></dd>
+ </s:fragment>
+ <s:fragment rendered="#{identity.hasPermission('security', 'view')}">
+ <dd><s:link value="Manage security" view="/security/security_manager.xhtml" /></dd>
+ </s:fragment>
+ </s:fragment>
+ <s:fragment rendered="#{identity.hasPermission('admin', null)}">
+ <dt>Global posts operations:</dt>
+ <hr />
+ <dd><s:link value="Fix html in all posts" action="#{adminBean.fixHtml}" /></dd>
+ <dd><s:link value="Remove duplicates" action="#{adminBean.removeDuplicates}" /></dd>
+ <dd><s:link value="Update missing templates" action="#{adminBean.updateMissingTemplates}" /></dd>
+ <dd><s:link value="Re-index posts (for search)" action="#{postSearch.reindex}" /></dd>
+ </s:fragment>
+ <dt>Existing feed operations:</dt>
+ <hr />
+ </dl>
+</div>
+
+<table border="0" width="100%" cellpadding="0" cellspacing="0" class="basetablestyle" style="margin-top:12px;">
+ <tr class="header">
+ <td class="tableheaderfirst" style="width:160px;">Feed title</td>
+ <td class="tableheader">Feed name</td>
+ <td class="tableheader">Feed type</td>
+ <td class="tableheader">Edit common feed properties</td>
+ <td class="tableheader">Edit feed-type-specific properties</td>
+ <td class="tableheader">Delete the feed</td>
+ </tr>
+
+ <ui:repeat var="group" value="#{groupsService.allGroups}">
+ <mamut:let var="acceptedFeeds" value="#{groupsService.acceptedFeeds(group)}">
+ <s:fragment rendered="#{acceptedFeeds.size() > 0 and
+ identity.hasPermission('management_group', 'view', group, acceptedFeeds)}">
+ <tr>
+ <td colspan="7" class="categoryRow">#{group.displayName}</td>
+ </tr>
+
+ <a:repeat var="feed" value="#{acceptedFeeds}" rowKeyVar="rowNumber">
+ <s:fragment rendered="#{identity.hasPermission('feed', 'edit', feed, group) ||
+ identity.hasPermission('feed', 'delete', feed, group)}">
+ <tr class="#{(rowNumber%2 == 0) ? 'evenRow' : 'oddRow'}">
+ <td class="rowlinefirst" style="font-weight:bold;">#{feed.title}</td>
+ <td class="rowline">#{feed.name}</td>
+ <td class="rowline">#{feedTypes.getFeedType(feed).name()}</td>
+ <td class="rowline">
+ <s:link view="/manage/feed_edit.xhtml" value="Edit common"
+ rendered="#{identity.hasPermission('feed', 'edit', feed, group)}">
+ <f:param name="name" value="#{feed.name}" />
+ </s:link>
+ </td>
+ <td class="rowline">
+ <s:link view="#{feedTypes.getFeedType(feed).editPage()}" value="Edit specific"
+ rendered="#{identity.hasPermission('feed', 'edit', feed, group)}">
+ <f:param name="name" value="#{feed.name}" />
+ </s:link>
+ </td>
+ <td class="rowline">
+ <s:link view="/manage/feed_delete.xhtml" action="#{feedMod.delete}" value="Delete"
+ onclick="if (!confirm('Are you sure you want to delete this feed?')) return false"
+ rendered="#{identity.hasPermission('feed', 'delete', feed, group)}">
+ <f:param name="name" value="#{feed.name}" />
+ </s:link>
+ </td>
+ </tr>
+ </s:fragment>
+ </a:repeat>
+ </s:fragment>
+ </mamut:let>
+ <mamut:let var="restrictedFeeds" value="#{feedsSecurity.filterViewableFeeds(groupsService.restrictedFeeds(group))}">
+ <s:fragment rendered="#{restrictedFeeds.size() > 0 and
+ identity.hasPermission('management_group', 'view', group, restrictedFeeds)}">
+ <tr>
+ <td colspan="7" class="categoryRow">#{group.displayName} (restricted)</td>
+ </tr>
+
+ <a:repeat var="feed" value="#{restrictedFeeds}">
+ <s:fragment rendered="#{(identity.hasPermission('feed', 'edit', feed, group) ||
+ identity.hasPermission('feed', 'delete', feed, group)) and
+ identity.hasPermission('feed', 'view', feed)}">
+ <tr class="evenRow">
+ <td class="rowlinefirst" style="font-weight:bold;">#{feed.title} (restricted)</td>
+ <td class="rowline">#{feed.name}</td>
+ <td class="rowline">#{feedTypes.getFeedType(feed).name()}</td>
+ <td class="rowline">
+ <s:link view="/manage/feed_edit.xhtml" value="Edit common"
+ rendered="#{identity.hasPermission('feed', 'edit', feed, group)}">
+ <f:param name="name" value="#{feed.name}" />
+ </s:link>
+ </td>
+ <td class="rowline">
+ <s:link view="#{feedTypes.getFeedType(feed).editPage()}" value="Edit specific"
+ rendered="#{identity.hasPermission('feed', 'edit', feed, group)}">
+ <f:param name="name" value="#{feed.name}" />
+ </s:link>
+ </td>
+ <td class="rowline">
+ <s:link view="/manage/feed_delete.xhtml" action="#{feedMod.delete}" value="Delete"
+ onclick="if (!confirm('Are you sure you want to delete this feed?')) return false"
+ rendered="#{identity.hasPermission('feed', 'delete', feed, group)}">
+ <f:param name="name" value="#{feed.name}" />
+ </s:link>
+ </td>
+ </tr>
+ </s:fragment>
+ </a:repeat>
+ </s:fragment>
+ </mamut:let>
+ </ui:repeat>
+</table>
+</ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/individual/individual_add.xhtml
===================================================================
--- feeds100P26/view/manage/individual/individual_add.xhtml (rev 0)
+++ feeds100P26/view/manage/individual/individual_add.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,21 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../../layout/template.xhtml">
+ <ui:define name="header">
+ Add a new individual posts feed - edit common data
+ </ui:define>
+
+ <ui:define name="body">
+ <ui:include src="../feed_mod.xhtml">
+ <ui:param name="new" value="true" />
+ <ui:param name="advanced" value="true" />
+ </ui:include>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/individual/individual_edit.xhtml
===================================================================
--- feeds100P26/view/manage/individual/individual_edit.xhtml (rev 0)
+++ feeds100P26/view/manage/individual/individual_edit.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,66 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../../layout/template.xhtml">
+ <ui:define name="header">
+ Edit individual posts feed: #{feedMod.feed.name}
+ </ui:define>
+
+ <ui:define name="body">
+ <div class="blogFeedNav #{additionalStyle}">
+ <ul>
+ <ui:include src="../../common/next_previous_navigation.xhtml">
+ <ui:param name="viewId" value="/manage/individual/individual_edit.xhtml" />
+ <ui:param name="navigationBean" value="#{individualFeedMod}" />
+ <ui:param name="showColon" value="false" />
+ </ui:include>
+ </ul>
+ </div>
+
+ <h:form>
+ <s:div rendered="#{individualFeedMod.individualPostsFeed.postInfos.size == 0}">
+ There are no posts included.
+ </s:div>
+
+ <s:div id="postsTable">
+ <table class="basetablestyle" >
+ <a:repeat rowKeyVar="rowNumber" var="postInfo"
+ value="#{individualFeedMod.postInfos}" rows="#{individualFeedMod.postsOnPage}">
+ <tr class="#{(rowNumber%2 == 0) ? 'evenRow' : 'oddRow'}">
+ <td>
+ <ui:include src="../../common/post.xhtml">
+ <ui:param name="post" value="#{postInfo.post}" />
+ <ui:param name="showSummary" value="true" />
+ <ui:param name="showAddToHighlights" value="false" />
+ </ui:include>
+ </td>
+ <td>
+ <h:commandLink value="Delete" action="#{individualFeedMod.delete(postInfo)}" />
+ </td>
+ </tr>
+ </a:repeat>
+ </table>
+ </s:div>
+
+ <s:div styleClass="formbuttons">
+ <ul>
+ <li>
+ <s:button value="Return" view="/manage/index.xhtml" propagation="end" styleClass="submit" />
+ </li>
+ <li>
+ <s:button value="Add a new post" view="/manage/individual/post_add.xhtml" styleClass="submit" />
+ </li>
+ <li>
+ <ui:include src="../../common/ajax_status.xhtml" />
+ </li>
+ </ul>
+ </s:div>
+ </h:form>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/individual/post_add.xhtml
===================================================================
--- feeds100P26/view/manage/individual/post_add.xhtml (rev 0)
+++ feeds100P26/view/manage/individual/post_add.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,91 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../../layout/template.xhtml">
+ <ui:define name="header">
+ Edit individual posts feed: #{feedMod.feed.name}
+ </ui:define>
+
+ <ui:define name="body">
+ <div class="adminforms">
+ <h:form>
+ <h:panelGrid columns="2" id="form_data">
+ <h:outputLabel><span class="required">*</span> Remote feed (atom/rss2) address:</h:outputLabel>
+ <h:panelGroup>
+ <h:inputText id="address" value="#{individualFeedMod.address}" required="true" size="55"
+ maxlength="64" disabled="#{individualFeedMod.parseOk}">
+ <s:validate />
+ </h:inputText>
+ <a:outputPanel id="addressMessage">
+ <h:message for="address" styleClass="error" />
+ </a:outputPanel>
+ </h:panelGroup>
+
+ <h:panelGroup />
+ <h:panelGroup id="parseStatus">
+ <h:message for="parse" infoClass="info" warnClass="error" errorClass="error" fatalClass="error" />
+ </h:panelGroup>
+
+ <h:outputLabel rendered="#{individualFeedMod.parseOk}">
+ <span class="required">*</span> Select post to include:
+ </h:outputLabel>
+ <h:panelGroup rendered="#{individualFeedMod.parseOk}">
+ <h:selectOneMenu id="selectPost" required="true" value="#{individualFeedMod.selectedPostTitleAsId}"
+ style="width: 500px">
+ <f:selectItems value="#{individualFeedMod.posts}" />
+ <s:validate />
+ <a:support event="onchange" reRender="postAuthorEdit,selectPostMessage"
+ action="#{individualFeedMod.updateSelectedPost}" />
+ </h:selectOneMenu>
+ <a:outputPanel id="selectPostMessage">
+ <h:message for="selectPost" styleClass="error" />
+ </a:outputPanel>
+ </h:panelGroup>
+
+ <h:outputLabel rendered="#{individualFeedMod.parseOk}">
+ <span class="required">*</span> Post author:
+ </h:outputLabel>
+ <h:panelGroup rendered="#{individualFeedMod.parseOk}" id="postAuthorEdit">
+ <h:inputText id="postAuthor" value="#{individualFeedMod.postAuthor}" required="true" size="55"
+ maxlength="64">
+ <s:validate />
+ </h:inputText>
+ <a:outputPanel id="postAuthorMessage">
+ <h:message for="postAuthor" styleClass="error" />
+ </a:outputPanel>
+ </h:panelGroup>
+ </h:panelGrid>
+
+ <s:div id="proceed" styleClass="formbuttons">
+ <ul>
+ <s:fragment rendered="#{!individualFeedMod.parseOk}">
+ <li>
+ <a:commandButton action="#{individualFeedMod.parseFeed}" value="Read and parse the feed"
+ styleClass="submit" id="parse"
+ reRender="form_data,proceed" />
+ </li>
+ </s:fragment>
+ <s:fragment rendered="#{individualFeedMod.parseOk}">
+ <li>
+ <h:commandButton value="Add post" action="#{individualFeedMod.addPost}"
+ styleClass="submit" />
+ </li>
+ </s:fragment>
+ <li>
+ <s:button value="Cancel" action="#{individualFeedMod.reset}" styleClass="submit" />
+ </li>
+ <li>
+ <ui:include src="../../common/ajax_status.xhtml" />
+ </li>
+ </ul>
+ </s:div>
+ </h:form>
+ </div>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/proposition/proposition_accept_1.xhtml
===================================================================
--- feeds100P26/view/manage/proposition/proposition_accept_1.xhtml (rev 0)
+++ feeds100P26/view/manage/proposition/proposition_accept_1.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,35 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../../layout/template.xhtml">
+ <ui:define name="header">
+ Accept feed: #{feedMod.feed.name}, remote feed-type-specific settings
+ </ui:define>
+
+ <ui:define name="body">
+ <div class="TwoColumnBlogSubnav">
+ <h4>Tips</h4>
+ <ul>
+ <li>
+ To see which posts will be saved, click "Read and parse the feed". You can also skip this step
+ by clicking "Save only 'Post author' and 'Include category'".
+ </li>
+ <li class="last">
+ #{messages['blog.feed.remote.mod.authors']}
+ </li>
+ </ul>
+ </div>
+
+ <ui:include src="../remote/remote_mod.xhtml">
+ <ui:param name="new" value="false" />
+ <ui:param name="showCaptcha" value="false" />
+ <ui:param name="backTo" value="/manage/proposition/proposition_list.xhtml" />
+ </ui:include>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/proposition/proposition_accept_2.xhtml
===================================================================
--- feeds100P26/view/manage/proposition/proposition_accept_2.xhtml (rev 0)
+++ feeds100P26/view/manage/proposition/proposition_accept_2.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,20 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../../layout/template.xhtml">
+ <ui:define name="header">
+ Accept feed: #{feedMod.feed.name}, common settings
+ </ui:define>
+
+ <ui:define name="body">
+ <ui:include src="../feed_mod.xhtml">
+ <ui:param name="new" value="false" />
+ </ui:include>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/proposition/proposition_list.xhtml
===================================================================
--- feeds100P26/view/manage/proposition/proposition_list.xhtml (rev 0)
+++ feeds100P26/view/manage/proposition/proposition_list.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,68 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../../layout/template.xhtml">
+ <ui:define name="header">
+ Manage feed propositions
+ </ui:define>
+
+ <ui:define name="body">
+ <table border="0" width="100%" cellpadding="0" cellspacing="0" class="basetablestyle" style="margin-top:12px;">
+ <tr class="header">
+ <td class="tableheaderfirst" style="width:160px;">Feed title</td>
+ <td class="tableheader">Feed name</td>
+ <td class="tableheader">Feed address</td>
+ <td class="tableheader">Feed category regexp</td>
+ <td class="tableheader">Feed author email</td>
+ <td class="tableheader">Accept the feed</td>
+ <td class="tableheader">Delete the feed</td>
+ </tr>
+
+ <ui:repeat var="group" value="#{groupsService.allGroups}">
+ <s:fragment rendered="#{identity.hasPermission('management_group', 'view', group, groupsService.acceptedFeeds(group))}">
+ <tr>
+ <td colspan="7" class="categoryRow">#{group.displayName}</td>
+ </tr>
+
+ <s:fragment rendered="#{groupsService.unacceptedFeeds(group).size() == 0}">
+ <tr>
+ <td colspan="7">There are no pending feed propositions.</td>
+ </tr>
+ </s:fragment>
+
+ <a:repeat var="feed" value="#{groupsService.unacceptedFeeds(group)}" rowKeyVar="rowNumber">
+ <s:fragment rendered="#{identity.hasPermission('feed', 'edit', feed, group) ||
+ identity.hasPermission('feed', 'delete', feed, group)}">
+ <tr class="#{(rowNumber%2 == 0) ? 'evenRow' : 'oddRow'}">
+ <td class="rowlinefirst" style="font-weight:bold;">#{feed.title}</td>
+ <td class="rowline">#{feed.name}</td>
+ <td class="rowline"><h:outputLink value="#{feed.remoteLink}">#{feed.remoteLink}</h:outputLink></td>
+ <td class="rowline">#{feed.includeCategoryRegexp}</td>
+ <td class="rowline">#{propositionsTools.getEmailForProposedFeed(feed)}</td>
+ <td class="rowline">
+ <s:link view="/manage/proposition/proposition_accept_1.xhtml" value="Accept"
+ rendered="#{identity.hasPermission('feed', 'edit', feed, group)}">
+ <f:param name="name" value="#{feed.name}" />
+ </s:link>
+ </td>
+ <td class="rowline">
+ <s:link view="/manage/feed_delete.xhtml" action="#{feedMod.delete}" value="Delete"
+ onclick="if (!confirm('Are you sure you want to delete this feed?')) return false"
+ rendered="#{identity.hasPermission('feed', 'delete', feed, group)}">
+ <f:param name="name" value="#{feed.name}" />
+ </s:link>
+ </td>
+ </tr>
+ </s:fragment>
+ </a:repeat>
+ </s:fragment>
+ </ui:repeat>
+ </table>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/remote/remote_add.xhtml
===================================================================
--- feeds100P26/view/manage/remote/remote_add.xhtml (rev 0)
+++ feeds100P26/view/manage/remote/remote_add.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,35 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../../layout/template.xhtml">
+ <ui:define name="header">
+ Add remote feed
+ </ui:define>
+
+ <ui:define name="body">
+ <div class="TwoColumnBlogSubnav">
+ <h4>Tips</h4>
+ <ul>
+ <li>
+ #{messages['blog.feed.remote.adding.quickstart']}
+ </li>
+ <li class="last">
+ #{messages['blog.feed.remote.mod.authors']}
+ </li>
+ </ul>
+ </div>
+
+ <ui:include src="remote_mod.xhtml">
+ <ui:param name="new" value="true" />
+ <ui:param name="inlineTips" value="false" />
+ <ui:param name="showCaptcha" value="false" />
+ <ui:param name="backTo" value="/manage/index.html" />
+ </ui:include>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/remote/remote_edit.xhtml
===================================================================
--- feeds100P26/view/manage/remote/remote_edit.xhtml (rev 0)
+++ feeds100P26/view/manage/remote/remote_edit.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,36 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../../layout/template.xhtml">
+ <ui:define name="header">
+ Edit remote feed: #{feedMod.feed.name}
+ </ui:define>
+
+ <ui:define name="body">
+ <div class="TwoColumnBlogSubnav">
+ <h4>Tips</h4>
+ <ul>
+ <li>
+ You can change the address of your feed, however use this option with caution; if you
+ have a completely new feed, maybe it's better to create a new remote feed instead?
+ </li>
+ <li class="last">
+ #{messages['blog.feed.remote.mod.authors']}
+ </li>
+ </ul>
+ </div>
+
+ <ui:include src="remote_mod.xhtml">
+ <ui:param name="new" value="false" />
+ <ui:param name="inlineTips" value="false" />
+ <ui:param name="showCaptcha" value="false" />
+ <ui:param name="backTo" value="/manage/index.html" />
+ </ui:include>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/remote/remote_mod.xhtml
===================================================================
--- feeds100P26/view/manage/remote/remote_mod.xhtml (rev 0)
+++ feeds100P26/view/manage/remote/remote_mod.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,156 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j">
+<div class="adminforms">
+<h:form>
+<h:panelGrid columns="2">
+ <h:panelGroup rendered="#{showCaptcha}">
+ <span class="required">*</span>
+ <h:graphicImage value="/seam/resource/captcha/#{captchaTools.id}" id="captchaGraphic"/>
+ </h:panelGroup>
+ <h:panelGroup rendered="#{showCaptcha}">
+ <h:inputText id="verifyCaptcha" value="#{captcha.response}" required="true">
+ <s:validate />
+ </h:inputText>
+ <a:outputPanel id="captchaMessage">
+ <h:message for="verifyCaptcha" styleClass="error" />
+ </a:outputPanel>
+ </h:panelGroup>
+
+ <h:outputLabel><span class="required">*</span> Remote feed (atom/rss2) address:</h:outputLabel>
+ <h:panelGroup id="addressBody">
+ <h:inputText id="link" value="#{remoteFeedMod.remoteFeed.remoteLink}" required="true" size="55"
+ maxlength="64" disabled="#{remoteFeedMod.parseOk}">
+ <s:validate />
+ </h:inputText>
+ <a:outputPanel id="linkMessage">
+ <h:message for="link" styleClass="error" />
+ </a:outputPanel>
+ </h:panelGroup>
+
+ <h:panelGroup rendered="#{inlineTips}" />
+ <h:panelGroup rendered="#{inlineTips}" styleClass="instructional_text">
+ <p>
+ #{messages['blog.feed.remote.adding.quickstart']}
+ After submitting, your feed will be added to the propositions queue and reviewed.
+ <br /><br />
+ If you are blogging on a wider area of subjects, please submit a feed of only jboss-related
+ entries (for example a feed of one category/ tag), or, if category information is included
+ in the entries of the feed, select a category after parsing the feed.
+ </p>
+ </h:panelGroup>
+
+ <h:outputLabel for="postAuthorType"><span class="required">*</span> How to determine posts authors:</h:outputLabel>
+ <h:panelGroup>
+ <h:selectOneMenu id="postAuthorType" value="#{remoteFeedMod.remoteFeed.postAuthorType}"
+ required="true" styleClass="selectwide">
+ <s:enumItem enumValue="BLOG_AUTHOR_IF_MISSING" label="Overwrite with blog author when post
+ author is missing" />
+ <s:enumItem enumValue="POST_AUTHOR" label="Always use original post author" />
+ <s:enumItem enumValue="BLOG_AUTHOR" label="Always overwrite post author with blog author" />
+ <s:convertEnum />
+ <s:validate />
+ </h:selectOneMenu>
+ </h:panelGroup>
+
+ <h:panelGroup rendered="#{inlineTips}" />
+ <h:panelGroup rendered="#{inlineTips}" styleClass="instructional_text">
+ <p>#{messages['blog.feed.remote.mod.authors']}</p>
+ </h:panelGroup>
+
+ <h:outputLabel id="includeCategoryHeader">
+ <s:fragment rendered="#{(remoteFeedMod.parseOk or !new) and (remoteFeedMod.includeCategories.size() > 2)}">
+ <span class="required">*</span> Include only posts from category:
+ </s:fragment>
+ </h:outputLabel>
+ <h:panelGroup id="includeCategoryBody">
+ <s:fragment rendered="#{(remoteFeedMod.parseOk or !new) and (remoteFeedMod.includeCategories.size() > 2)}">
+ <h:selectOneMenu id="includeCategory" required="true" value="#{remoteFeedMod.includeCategory}"
+ style="width: 200px">
+ <f:selectItems value="#{remoteFeedMod.includeCategories}" />
+ <s:validate />
+ <a:support event="onchange" reRender="includeCategoryBody,postsIncluded" ajaxSingle="true"
+ action="#{remoteFeedMod.generateVisiblePosts}" />
+ </h:selectOneMenu>
+ <h:inputText id="includeOtherCategory" rendered="#{remoteFeedMod.includeCategory == 'OTHER'}"
+ value="#{remoteFeedMod.includeOtherCategoryRegexp}" required="true">
+ <s:validate />
+ <a:support event="onblur" reRender="includeCategoryMessage,postsIncluded" ajaxSingle="true"
+ action="#{remoteFeedMod.generateVisiblePosts}" />
+ </h:inputText>
+ <a:outputPanel id="includeCategoryMessage">
+ <h:message for="includeCategory" styleClass="error" />
+ <h:message for="includeOtherCategory" styleClass="error" />
+ </a:outputPanel>
+ </s:fragment>
+ </h:panelGroup>
+
+ <h:panelGroup />
+ <h:panelGroup id="parseStatus">
+ <h:message for="parse" infoClass="info" warnClass="error" errorClass="error" fatalClass="error" />
+ </h:panelGroup>
+</h:panelGrid>
+
+<s:div id="proceed" styleClass="formbuttons">
+ <ul>
+ <s:fragment rendered="#{!remoteFeedMod.parseOk}">
+ <li>
+ <a:commandButton action="#{remoteFeedMod.parseFeed}" value="Read and parse the feed"
+ styleClass="submit" id="parse"
+ reRender="parseStatus,proceed,linkMessage,link,captchaGraphic,captchaMessage,postAuthorType,includeCategoryHeader,includeCategoryBody,addressBody,postsIncluded" />
+ </li>
+ </s:fragment>
+ <s:fragment rendered="#{remoteFeedMod.parseOk and new}">
+ <li>
+ <h:commandButton value="Next »" action="#{remoteFeedMod.saveNew}"
+ styleClass="submit" />
+ </li>
+ </s:fragment>
+ <s:fragment rendered="#{remoteFeedMod.parseOk and !new}">
+ <li>
+ <h:commandButton value="Save" action="#{remoteFeedMod.saveExisting}"
+ styleClass="submit" />
+ </li>
+ </s:fragment>
+ <s:fragment rendered="#{!remoteFeedMod.parseOk and !new}">
+ <li>
+ <h:commandButton value="Save only 'Post author' and 'Include category'" action="#{remoteFeedMod.savePartial}"
+ styleClass="submit" />
+ </li>
+ </s:fragment>
+ <li>
+ <s:button value="Cancel" view="#{backTo}" propagation="end" styleClass="submit" />
+ </li>
+ <li>
+ <ui:include src="../../common/ajax_status.xhtml" />
+ </li>
+ </ul>
+</s:div>
+
+<s:div id="postsIncluded">
+ <s:fragment rendered="#{remoteFeedMod.parseOk}">
+ <h4>
+ <s:fragment rendered="#{new}">
+ The following posts will be saved initially:
+ </s:fragment>
+ <s:fragment rendered="#{!new}">
+ The following posts will be merged into current posts on the next update, after saving:
+ </s:fragment>
+ </h4>
+
+ <ul>
+ <ui:repeat var="post" value="#{remoteFeedMod.visiblePosts}">
+ <li><a href="#{post.link}">#{post.title}</a></li>
+ </ui:repeat>
+ </ul>
+ </s:fragment>
+</s:div>
+</h:form>
+</div>
+</ui:composition>
Added: feeds100P26/view/manage/remote/remote_propose.xhtml
===================================================================
--- feeds100P26/view/manage/remote/remote_propose.xhtml (rev 0)
+++ feeds100P26/view/manage/remote/remote_propose.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,23 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../../layout/template.xhtml">
+ <ui:define name="header">
+ Propose a blog
+ </ui:define>
+
+ <ui:define name="body">
+ <ui:include src="remote_mod.xhtml">
+ <ui:param name="new" value="true" />
+ <ui:param name="inlineTips" value="true" />
+ <ui:param name="showCaptcha" value="true" />
+ <ui:param name="backTo" value="/home.xhtml" />
+ </ui:include>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/shotoku/shotoku_add.page.xml
===================================================================
--- feeds100P26/view/manage/shotoku/shotoku_add.page.xml (rev 0)
+++ feeds100P26/view/manage/shotoku/shotoku_add.page.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,6 @@
+<page view-id="/manage/shotoku/shotoku_add.xhtml" login-required="true">
+ <begin-conversation flush-mode="manual" join="true" />
+ <navigation from-action="#{shotokuFeedMod.saveNew}">
+ <redirect view-id="/manage/feed_add.xhtml" />
+ </navigation>
+</page>
Added: feeds100P26/view/manage/shotoku/shotoku_add.xhtml
===================================================================
--- feeds100P26/view/manage/shotoku/shotoku_add.xhtml (rev 0)
+++ feeds100P26/view/manage/shotoku/shotoku_add.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,20 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../../layout/template.xhtml">
+ <ui:define name="header">
+ Add a Shotoku feed
+ </ui:define>
+
+ <ui:define name="body">
+ <ui:include src="shotoku_mod.xhtml">
+ <ui:param name="new" value="true" />
+ </ui:include>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/shotoku/shotoku_edit.page.xml
===================================================================
--- feeds100P26/view/manage/shotoku/shotoku_edit.page.xml (rev 0)
+++ feeds100P26/view/manage/shotoku/shotoku_edit.page.xml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,9 @@
+<page view-id="/manage/shotoku/shotoku_edit.xhtml" login-required="true">
+ <begin-conversation flush-mode="manual" join="true" />
+ <param name="name" converterId="feedConverter" value="#{feedMod.feed}" />
+ <restrict>#{identity.hasPermission('feed', 'edit', feedMod.feed, feedMod.feed.group)}</restrict>
+ <navigation from-action="#{shotokuFeedMod.saveExisting}">
+ <end-conversation />
+ <redirect view-id="/manage/index.xhtml" />
+ </navigation>
+</page>
\ No newline at end of file
Added: feeds100P26/view/manage/shotoku/shotoku_edit.xhtml
===================================================================
--- feeds100P26/view/manage/shotoku/shotoku_edit.xhtml (rev 0)
+++ feeds100P26/view/manage/shotoku/shotoku_edit.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,20 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../../layout/template.xhtml">
+ <ui:define name="header">
+ Edit shotoku feed: #{feedMod.feed.name}
+ </ui:define>
+
+ <ui:define name="body">
+ <ui:include src="shotoku_mod.xhtml">
+ <ui:param name="new" value="false" />
+ </ui:include>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/shotoku/shotoku_mod.xhtml
===================================================================
--- feeds100P26/view/manage/shotoku/shotoku_mod.xhtml (rev 0)
+++ feeds100P26/view/manage/shotoku/shotoku_mod.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,153 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j">
+<div class="TwoColumnBlogSubnav">
+ <h4>Tips</h4>
+ <ul>
+ <li>
+ You can convert files from a directory in SVN to posts using Shotoku.
+ The conversion is as follows:
+ <br />
+ <br />
+ <i>post title</i> - value of the 'title' property of the file
+ <br />
+ <br />
+ <i>post author</i> - value of the 'author' property; however if all posts have the
+ same author, you can omit this, then the value of the author field for the feed will be used
+ <br />
+ <br />
+ <i>post content</i> - file content
+ </li>
+ <li>
+ Podcasts are also easy to create. The conversion is a little bit different:
+ <br />
+ <br />
+ <i>post content</i> - value of the 'description' property
+ <br />
+ <br />
+ <i>post enclosure</i> - the file forms the enclosure; however you need to provide
+ the link, from which this file can be downloaded, by providing a relative URL directory, to
+ which the name of the file will be appended
+ <br />
+ <br />
+ <i>post image (optional)</i> - value of the 'thumbnail' property (also a relative URL)
+ </li>
+ <li id="last">
+ #{messages['blog.feed.remote.mod.authors']}
+ </li>
+ </ul>
+</div>
+
+<div class="adminforms">
+<h:form>
+<h:panelGrid columns="2">
+ <h:outputLabel><span class="required">*</span> Content manager id:</h:outputLabel>
+ <h:panelGroup>
+ <h:inputText id="cmId" value="#{shotokuFeedMod.shotokuFeed.cmId}" required="true" size="55"
+ maxlength="64">
+ <s:validate />
+ </h:inputText>
+ <a:outputPanel id="cmIdMessage">
+ <h:message for="cmId" styleClass="error" />
+ </a:outputPanel>
+ </h:panelGroup>
+
+ <h:outputLabel><span class="required">*</span> Path:</h:outputLabel>
+ <h:panelGroup>
+ <h:inputText id="cmPath" value="#{shotokuFeedMod.shotokuFeed.cmPath}" required="true" size="55"
+ maxlength="64">
+ <s:validate />
+ </h:inputText>
+ <a:outputPanel id="cmPathMessage">
+ <h:message for="cmPath" styleClass="error" />
+ </a:outputPanel>
+ </h:panelGroup>
+
+ <h:outputLabel>This is a podcast:</h:outputLabel>
+ <h:panelGroup>
+ <h:selectBooleanCheckbox id="podcast" value="#{shotokuFeedMod.podcast}" required="true">
+ <a:support event="onchange" reRender="podcastPrefix" ajaxSingle="true"
+ bypassUpdates="false"/>
+ <s:validate />
+ </h:selectBooleanCheckbox>
+ <a:outputPanel id="podcastMessage">
+ <h:message for="podcast" styleClass="error" />
+ </a:outputPanel>
+ </h:panelGroup>
+
+ <h:outputLabel>
+ URL prefix for podcast files:
+ </h:outputLabel>
+ <h:panelGroup>
+ <h:inputText id="podcastPrefix" value="#{shotokuFeedMod.shotokuFeed.podcastPrefix}"
+ disabled="#{!shotokuFeedMod.podcast}" required="#{shotokuFeedMod.podcast}">
+ <s:validate />
+ </h:inputText>
+ <a:outputPanel id="podcastPrefixMessage">
+ <h:message for="podcastPrefix" styleClass="error" />
+ </a:outputPanel>
+ </h:panelGroup>
+
+ <h:outputLabel for="postAuthorType"><span class="required">*</span> Post author:</h:outputLabel>
+ <h:panelGroup>
+ <h:selectOneMenu id="postAuthorType" value="#{shotokuFeedMod.shotokuFeed.postAuthorType}"
+ required="true" styleClass="selectwide">
+ <s:enumItem enumValue="BLOG_AUTHOR_IF_MISSING" label="Overwrite with blog author when post
+ author is missing" />
+ <s:enumItem enumValue="POST_AUTHOR" label="Always use original post author" />
+ <s:enumItem enumValue="BLOG_AUTHOR" label="Always overwrite post author with blog author" />
+ <s:convertEnum />
+ <s:validate />
+ </h:selectOneMenu>
+ </h:panelGroup>
+
+ <h:panelGroup />
+ <h:panelGroup id="checkStatus">
+ <h:panelGroup rendered="#{shotokuFeedMod.pathOk}">
+ Checking the path was successfull! You can proceed.
+ </h:panelGroup>
+ <h:panelGroup rendered="#{!shotokuFeedMod.pathOk and shotokuFeedMod.pathException != null}">
+ Checking the path failed, because of the following exception:
+ #{shotokuFeedMod.pathException.message}
+ </h:panelGroup>
+ </h:panelGroup>
+</h:panelGrid>
+
+<s:div id="proceed" styleClass="formbuttons">
+ <ul>
+ <s:fragment rendered="#{!shotokuFeedMod.pathOk}">
+ <li>
+ <a:commandButton action="#{shotokuFeedMod.checkPath}" value="Check the path"
+ styleClass="submit"
+ reRender="checkStatus,proceed,cmId,cmIdMessage,cmPath,cmPathMessage,podcast,podcastMessage,podcastPrefix,podcastPrefixMessage" />
+ </li>
+ </s:fragment>
+ <s:fragment rendered="#{shotokuFeedMod.pathOk and new}">
+ <li>
+ <h:commandButton value="Next »" action="#{shotokuFeedMod.saveNew}"
+ styleClass="submit" />
+ </li>
+ </s:fragment>
+ <s:fragment rendered="#{shotokuFeedMod.pathOk and !new}">
+ <li>
+ <h:commandButton value="Save" action="#{shotokuFeedMod.saveExisting}"
+ styleClass="submit" />
+ </li>
+ </s:fragment>
+ <li>
+ <s:button value="Cancel" view="/manage/index.xhtml" propagation="end" styleClass="submit" />
+ </li>
+ <li>
+ <ui:include src="../../common/ajax_status.xhtml" />
+ </li>
+ </ul>
+</s:div>
+</h:form>
+</div>
+</ui:composition>
Added: feeds100P26/view/manage/template/template_add.xhtml
===================================================================
--- feeds100P26/view/manage/template/template_add.xhtml (rev 0)
+++ feeds100P26/view/manage/template/template_add.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,20 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../../layout/template.xhtml">
+ <ui:define name="header">
+ Add a new template
+ </ui:define>
+
+ <ui:define name="body">
+ <ui:include src="template_mod.xhtml">
+ <ui:param name="new" value="true" />
+ </ui:include>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/template/template_edit.xhtml
===================================================================
--- feeds100P26/view/manage/template/template_edit.xhtml (rev 0)
+++ feeds100P26/view/manage/template/template_edit.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,20 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../../layout/template.xhtml">
+ <ui:define name="header">
+ Edit template: #{templateMod.template.name}
+ </ui:define>
+
+ <ui:define name="body">
+ <ui:include src="template_mod.xhtml">
+ <ui:param name="new" value="false" />
+ </ui:include>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/template/template_list.xhtml
===================================================================
--- feeds100P26/view/manage/template/template_list.xhtml (rev 0)
+++ feeds100P26/view/manage/template/template_list.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,51 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../../layout/template.xhtml">
+ <ui:define name="header">
+ Manage templates
+ </ui:define>
+
+ <ui:define name="body">
+ <div class="adminlist">
+ <dl>
+ <dd><s:link value="Add new template" view="/manage/template/template_add.xhtml" /></dd>
+ <dt>Current templates:</dt>
+ <hr />
+ </dl>
+ </div>
+
+ <table border="0" cellpadding="4" cellspacing="0" class="basetablestyle" style="margin-top:12px;">
+ <tr class="header">
+ <td class="tableheaderfirst" style="width:160px;">Template name</td>
+ <td class="tableheader">Template type</td>
+ <td class="tableheader" />
+ <td class="tableheader" />
+ </tr>
+
+ <a:repeat var="template" value="#{templateService.allTemplates}" rowKeyVar="rowNumber">
+ <tr class="#{(rowNumber%2 == 0) ? 'evenRow' : 'oddRow'}">
+ <td class="rowlinefirst" style="font-weight:bold;">#{template.name}</td>
+ <td class="rowline">#{template.type}</td>
+ <td class="rowline">
+ <s:link view="/manage/template/template_edit.xhtml" value="Edit">
+ <f:param name="id" value="#{template.id}" />
+ </s:link>
+ </td>
+ <td class="rowline">
+ <s:link view="/manage/template/template_delete.xhtml" action="#{templateMod.delete}" value="Delete"
+ onclick="if (!confirm('Are you sure you want to delete this template?')) return false">
+ <f:param name="id" value="#{template.id}" />
+ </s:link>
+ </td>
+ </tr>
+ </a:repeat>
+ </table>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/manage/template/template_mod.xhtml
===================================================================
--- feeds100P26/view/manage/template/template_mod.xhtml (rev 0)
+++ feeds100P26/view/manage/template/template_mod.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,104 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:blog="http://jboss.org/blog/tags"
+ xmlns:a="http://richfaces.org/a4j">
+ <div class="adminforms">
+ <h:form>
+ <h:panelGrid columns="2">
+ <h:outputLabel for="name"><span class="required">*</span> Name:</h:outputLabel>
+ <h:panelGroup>
+ <h:inputText id="name" value="#{templateMod.template.name}" required="true" size="32">
+ <blog:uniqueTemplateNameValidator entityId="#{templateMod.template.id}" />
+ <a:support event="onblur" reRender="nameMessage" ajaxSingle="true" bypassUpdates="true"/>
+ <s:validate />
+ </h:inputText>
+
+ <a:outputPanel id="nameMessage">
+ <h:message for="name" styleClass="error" />
+ </a:outputPanel>
+ </h:panelGroup>
+
+ <h:outputLabel for="type"><span class="required">*</span> Template type:</h:outputLabel>
+ <h:panelGroup>
+ <h:selectOneMenu id="type" value="#{templateMod.template.type}" required="true"
+ styleClass="selectnarrow">
+ <s:enumItem enumValue="ATOM" />
+ <s:enumItem enumValue="RSS2" />
+ <s:convertEnum />
+ <a:support event="onchange" reRender="typeMessage" ajaxSingle="true" />
+ <s:validate />
+ </h:selectOneMenu>
+
+ <a:outputPanel id="typeMessage">
+ <h:message for="type" styleClass="error" />
+ </a:outputPanel>
+ </h:panelGroup>
+
+ <h:outputLabel for="text"><span class="required">*</span> Text:</h:outputLabel>
+ <h:panelGroup>
+ <h:inputTextarea id="text" value="#{templateMod.template.text}" rows="40" cols="100" required="true">
+ <a:support event="onblur" reRender="textMessage" ajaxSingle="true" bypassUpdates="true"/>
+ <s:validate />
+ </h:inputTextarea>
+
+ <a:outputPanel id="textMessage">
+ <h:message for="text" styleClass="error" />
+ </a:outputPanel>
+ </h:panelGroup>
+ </h:panelGrid>
+
+
+ <div id="proceed" class="formbuttons">
+ <ul>
+ <s:fragment rendered="#{new}">
+ <li>
+ <h:commandButton value="Add" action="#{templateMod.saveNew}" styleClass="submit" />
+ </li>
+ </s:fragment>
+ <s:fragment rendered="#{!new}">
+ <li>
+ <h:commandButton value="Save" action="#{templateMod.saveExisting}" styleClass="submit" />
+ </li>
+ </s:fragment>
+ <li>
+ <s:button value="Cancel" view="/manage/template/template_list.xhtml" propagation="end"
+ styleClass="submit" />
+ </li>
+ </ul>
+ </div>
+ </h:form>
+
+ <p>
+ When creating a template, the context contains the following variables:
+ </p>
+ <ul>
+ <li>$feed - the <code>org.jboss.blog.model.Feed</code> object, for which the feed is being generated</li>
+ <li>$posts - a list of <code>org.jboss.blog.model.Post</code> objects, which is the list of posts
+ for the feed</li>
+ <li>$xmlType - the type of the template being generated (one of the enum values
+ <code>org.jboss.blog.model.TemplateType</code>)</li>
+ <li>$tools - a utility object containing the following functions:
+ <ul>
+ <li>$tools.formatDate(java.util.Date) - formats the date using a format appropriate for this
+ template type</li>
+ <li>$tools.feedPubDate(org.jboss.blog.model.Feed, java.util.List<org.jboss.blog.model.Post> -
+ generates the feed publish date, which is the published date of the newest post</li>
+ <li>$tools.feedPageLink(org.jboss.blog.model.Feed) - generates a link to the html version of the
+ given feed</li>
+ <li>$tools.feedLink(org.jboss.blog.model.Feed, org.jboss.blog.model.TemplateType) - generates
+ a link to a feed of the given type</li>
+ <li>$tools.postLink(org.jboss.blog.model.Post) - generates a link to the html version of the
+ given post</li>
+ <li>$tools.escape(java.util.String) - escapes special charaters, like &, which can be
+ found in links</li>
+ </ul>
+ </li>
+ </ul>
+ </div>
+</ui:composition>
Added: feeds100P26/view/manage/update_manager.xhtml
===================================================================
--- feeds100P26/view/manage/update_manager.xhtml (rev 0)
+++ feeds100P26/view/manage/update_manager.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,140 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../layout/template.xhtml">
+<ui:define name="header">
+ Update manager
+</ui:define>
+<ui:define name="body">
+<h:form>
+ <a:poll interval="5000" reRender="mainTable" />
+ <a:outputPanel id="mainTable">
+ <table cellspacing="5" class="deftable" width="75%">
+ <tr>
+ <td class="term" width="15%">Last page refresh:</td>
+ <td class="def">#{updateManager.now}</td>
+ </tr>
+ <tr>
+ <td class="term" width="15%">Last update start:</td>
+ <td class="def">#{updateManager.lastUpdateStartDate}</td>
+ </tr>
+ <tr>
+ <td class="term" width="15%">Last update end:</td>
+ <td class="def">#{updateManager.lastUpdateEndDate}</td>
+ </tr>
+ <tr>
+ <td class="term" width="15%">Update in progress:</td>
+ <td class="def">#{updateManager.updateInProgress.get()}</td>
+ </tr>
+ <tr>
+ <td class="term" width="15%">Global exceptions:</td>
+ <td class="def">
+ <s:fragment rendered="#{updateManager.globalExceptions.size() == 0}">
+ None
+ </s:fragment>
+ <s:fragment rendered="#{updateManager.globalExceptions.size() > 0}">
+ <ui:repeat var="exception" value="#{updateManager.globalExceptions}">
+ <rich:togglePanel id="stackTracePanel" initialState="nothing" switchType="client"
+ stateOrder="nothing,stackTrace">
+ <f:facet name="nothing">
+ <s:fragment>
+ #{exception.message}
+ </s:fragment>
+ </f:facet>
+ <f:facet name="stackTrace">
+ <s:fragment>
+ #{exception.message} <br />
+ #{updateManager.getExceptionStackTrace(exception)}
+ </s:fragment>
+ </f:facet>
+ </rich:togglePanel>
+ <rich:toggleControl for="stackTracePanel" value="Toggle stack trace"/>
+ </ui:repeat>
+ </s:fragment>
+ </td>
+ </tr>
+ <tr>
+ <td class="term" width="15%">Feed exceptions:</td>
+ <td class="def">
+ <s:fragment rendered="#{updateManager.feedUpdateExceptionNames.size() == 0}">
+ None
+ </s:fragment>
+ <s:fragment rendered="#{updateManager.feedUpdateExceptionNames.size() > 0}">
+ <ui:repeat var="feedName" value="#{updateManager.feedUpdateExceptionNames}">
+ <strong>#{feedName}</strong> <br />
+ <ui:repeat var="exception"
+ value="#{updateManager.getFeedUpdateExceptionsForFeed(feedName)}">
+ <rich:togglePanel id="stackTracePanel" initialState="nothing" switchType="client"
+ stateOrder="nothing,stackTrace">
+ <f:facet name="nothing">
+ <s:fragment>
+ #{exception.message}
+ </s:fragment>
+ </f:facet>
+ <f:facet name="stackTrace">
+ <s:fragment>
+ #{exception.message} <br />
+ #{updateManager.getExceptionStackTrace(exception)}
+ </s:fragment>
+ </f:facet>
+ </rich:togglePanel>
+ <rich:toggleControl for="stackTracePanel" value="Toggle stack trace"/>
+ <br />
+ </ui:repeat>
+ <br />
+ </ui:repeat>
+ </s:fragment>
+ </td>
+ </tr>
+ <tr>
+ <td class="term" width="15%">Actions:</td>
+ <td class="def">
+ <h:commandLink action="#{updateManager.clearGlobalExceptions}"
+ value="Clear global exceptions" /><br />
+ <h:commandLink action="#{updateManager.clearFeedsExceptions}"
+ value="Clear feeds exceptions"/><br />
+ <h:commandLink action="#{updateManager.restartUpdateThread}"
+ value="Restart the update thread"/><br />
+ </td>
+ </tr>
+ </table>
+ <div class="formbuttons" />
+ </a:outputPanel>
+</h:form>
+<h:form>
+ <table cellspacing="5" class="deftable" width="75%">
+ <tr>
+ <td class="term" width="15%">Updates interval (in seconds):</td>
+ <td class="def">
+ <h:inputText value="#{updateManager.updateInterval}"/>
+ </td>
+ </tr>
+ <tr>
+ <td class="term" width="15%">Remote feed read timeout (in milliseconds):</td>
+ <td class="def">
+ <h:inputText value="#{updateManager.readTimeout}"/>
+ </td>
+ </tr>
+ <tr>
+ <td class="term" width="15%">Remote feed connection timeout (in milliseconds):</td>
+ <td class="def">
+ <h:inputText value="#{updateManager.connectionTimeout}"/>
+ </td>
+ </tr>
+ </table>
+ <div class="formbuttons">
+ <ul>
+ <li>
+ <h:commandButton value="Save changes" action="#{updateManager.save}" styleClass="submit" />
+ </li>
+ </ul>
+ </div>
+</h:form>
+</ui:define>
+</ui:composition>
Added: feeds100P26/view/search/search.xhtml
===================================================================
--- feeds100P26/view/search/search.xhtml (rev 0)
+++ feeds100P26/view/search/search.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,50 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ template="../layout/template.xhtml">
+ <ui:define name="header">
+ Search
+ </ui:define>
+
+ <ui:define name="body">
+ <div class="blogContent">
+ <s:div rendered="#{empty postSearch.results}">
+ <p>
+ Your search for: '#{postSearch.query}' didn't return any results.
+ </p>
+ </s:div>
+
+ <s:div rendered="#{not empty postSearch.results}">
+ <p>
+ Your search for: '#{postSearch.query}' returned #{postSearch.resultsCount} results.
+ </p>
+
+ <div class="blogFeedNav">
+ <ul>
+ <ui:include src="../common/next_previous_navigation.xhtml">
+ <ui:param name="viewId" value="/search/search.xhtml" />
+ <ui:param name="navigationBean" value="#{postSearch}" />
+ <ui:param name="showColon" value="false" />
+ </ui:include>
+ </ul>
+ </div>
+
+ <ui:repeat var="result" value="#{postSearch.results}">
+ <ui:include src="../common/post.xhtml">
+ <ui:param name="post" value="#{result[1]}" />
+ <ui:param name="showSummary" value="true" />
+ <ui:param name="showAddToHighlights" value="false" />
+ <ui:param name="showPostTo" value="false" />
+ <ui:param name="additionalHeader"
+ value="(#{postSearch.formatScore(result[0])}%)" />
+ </ui:include>
+ </ui:repeat>
+ </s:div>
+ </div>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/security/account.xhtml
===================================================================
--- feeds100P26/view/security/account.xhtml (rev 0)
+++ feeds100P26/view/security/account.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,44 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ template="../layout/template.xhtml">
+ <ui:define name="header">
+ Account for user #{identity.username}
+ </ui:define>
+
+ <ui:define name="body">
+ <div class="TwoColumnBlogSubnav">
+ <h4>Tips</h4>
+ <ul>
+ <li class="last">
+ The security key is used to view restricted feeds, without the need to log in.
+ Don't distribute it, or addresses to restricted feeds viewed using this key!
+ </li>
+ </ul>
+ </div>
+
+ <div class="adminforms">
+ <h:form>
+ <h:panelGrid columns="2">
+ <h:outputLabel for="username">Security key:</h:outputLabel>
+ <h:inputText id="username" value="#{identity.securityUser.restrictedKey}" disabled="true" />
+ </h:panelGrid>
+
+ <div class="formbuttons">
+ <ul>
+ <li>
+ <h:commandButton value="Re-generate the security key"
+ action="#{securityUserKeys.generateKeyForCurrentUser()}"
+ styleClass="submit" />
+ </li>
+ </ul>
+ </div>
+ </h:form>
+ </div>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/security/login.xhtml
===================================================================
--- feeds100P26/view/security/login.xhtml (rev 0)
+++ feeds100P26/view/security/login.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,52 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ template="../layout/template.xhtml">
+ <ui:define name="header">
+ Login
+ </ui:define>
+
+ <ui:define name="body">
+ <div class="TwoColumnBlogSubnav">
+ <h4>Tips</h4>
+ <ul>
+ <li>
+ If you don't have an account yet, click the 'Register' link at the top.
+ </li>
+ <li class="last">
+ If you have registered, but can't login, you may not have a JBoss.ORG account yet.
+ To get one, just login once to JBoss.ORG (<a href="http://labs.jboss.com/auth">here</a>),
+ it will be created automatically.
+ </li>
+ </ul>
+ </div>
+
+ <div class="adminforms">
+ <h:form>
+ <h:panelGrid columns="2">
+ <h:outputLabel for="username">Username</h:outputLabel>
+ <h:inputText id="username" value="#{identity.username}"/>
+
+ <h:outputLabel for="password">Password</h:outputLabel>
+ <h:inputSecret id="password" value="#{identity.password}"/>
+ </h:panelGrid>
+
+ <div class="formbuttons">
+ <ul>
+ <li>
+ <h:commandButton value="Login" action="#{identity.login}" styleClass="submit" />
+ </li>
+ <li>
+ <s:button value="Cancel" view="/home.xhtml" styleClass="submit" propagation="none" />
+ </li>
+ </ul>
+ </div>
+ </h:form>
+ </div>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/security/security_group_add.xhtml
===================================================================
--- feeds100P26/view/security/security_group_add.xhtml (rev 0)
+++ feeds100P26/view/security/security_group_add.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,39 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../layout/template.xhtml">
+ <ui:define name="header">
+ Select group to add:
+ </ui:define>
+ <ui:define name="body">
+ <h:form>
+ <div class="adminforms">
+ <br />
+ <h:panelGrid columns="1">
+ <h:selectOneListbox required="true" value="#{securityMod.restrictedSecurityGroup}"
+ converter="securityGroupConverter">
+ <s:selectItems var="group" value="#{externalSecurityService.allGroups}"
+ label="#{externalSecurityService.getDisplayName(group)}" />
+ </h:selectOneListbox>
+ </h:panelGrid>
+
+ <div class="formbuttons">
+ <ul>
+ <li>
+ <h:commandButton value="Add" styleClass="submit" action="#{securityMod.addSecurityGroup}" />
+ </li>
+ <li>
+ <s:button value="Cancel" view="/security/security_manager.xhtml" styleClass="submit" />
+ </li>
+ </ul>
+ </div>
+ </div>
+ </h:form>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/security/security_manager.xhtml
===================================================================
--- feeds100P26/view/security/security_manager.xhtml (rev 0)
+++ feeds100P26/view/security/security_manager.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,222 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../layout/template.xhtml">
+<ui:define name="header">
+ Security manager
+</ui:define>
+<ui:define name="body">
+
+<s:fragment rendered="#{identity.hasPermission('admin', null)}">
+ <h3>Administrators:</h3>
+
+ <table cellspacing="5" class="deftable" width="75%">
+ <tr>
+ <td class="term" width="15%" />
+ <td class="def">
+ <ul>
+ <ui:repeat var="securityGroup" value="#{securityMod.administratorGroups}">
+ <li>
+ #{externalSecurityService.getDisplayName(securityGroup)}
+ (
+ <s:link value="delete" action="#{securityMod.deleteSecurityGroup}">
+ <f:param name="role" value="ADMIN" />
+ <f:param name="securityGroup" value="#{securityGroup.externalId}" />
+ </s:link>
+ )
+ </li>
+ </ui:repeat>
+
+ <s:link value="Add user group" view="/security/security_group_add.xhtml">
+ <f:param name="role" value="ADMIN" />
+ </s:link>
+ </ul>
+ </td>
+ <td class="def">
+ <ul>
+ <ui:repeat var="securityUser" value="#{securityMod.administratorUsers}">
+ <li>
+ #{externalSecurityService.getDisplayName(securityUser)}
+ (
+ <s:link value="delete" action="#{securityMod.deleteSecurityUser}">
+ <f:param name="role" value="ADMIN" />
+ <f:param name="securityUser" value="#{securityUser.externalId}" />
+ </s:link>
+ )
+ </li>
+ </ui:repeat>
+
+ <s:link value="Add user" view="/security/security_user_add.xhtml">
+ <f:param name="role" value="ADMIN" />
+ </s:link>
+ </ul>
+ </td>
+ </tr>
+ </table>
+</s:fragment>
+
+<h3>Feed groups administrators:</h3>
+
+<table cellspacing="5" class="deftable" width="75%">
+ <ui:repeat var="group" value="#{groupsService.allGroups}">
+ <s:fragment rendered="#{identity.hasPermission('management_group', 'view', group)}">
+ <tr>
+ <td class="term" width="15%">#{group.displayName}</td>
+ <td class="def">
+ <ui:repeat var="securityGroup" value="#{securityMod.getGroupAdministratorGroups(group)}">
+ <li>
+ #{externalSecurityService.getDisplayName(securityGroup)}
+ (
+ <s:link value="delete" action="#{securityMod.deleteSecurityGroup}">
+ <f:param name="role" value="GROUP_ADMIN" />
+ <f:param name="group" value="#{group.id}" />
+ <f:param name="securityGroup" value="#{securityGroup.externalId}" />
+ </s:link>
+ )
+ </li>
+ </ui:repeat>
+
+ <s:link value="Add user group" view="/security/security_group_add.xhtml">
+ <f:param name="role" value="GROUP_ADMIN" />
+ <f:param name="group" value="#{group.id}" />
+ </s:link>
+ </td>
+ <td class="def">
+ <ui:repeat var="securityUser" value="#{securityMod.getGroupAdministratorUsers(group)}">
+ <li>
+ #{externalSecurityService.getDisplayName(securityUser)}
+ (
+ <s:link value="delete" action="#{securityMod.deleteSecurityUser}">
+ <f:param name="role" value="GROUP_ADMIN" />
+ <f:param name="group" value="#{group.id}" />
+ <f:param name="securityUser" value="#{securityUser.externalId}" />
+ </s:link>
+ )
+ </li>
+ </ui:repeat>
+
+ <s:link value="Add user" view="/security/security_user_add.xhtml">
+ <f:param name="role" value="GROUP_ADMIN" />
+ <f:param name="group" value="#{group.id}" />
+ </s:link>
+ </td>
+ </tr>
+ </s:fragment>
+ </ui:repeat>
+</table>
+
+<h3>Feed administrators:</h3>
+
+<ui:repeat var="group" value="#{groupsService.allGroups}">
+ <s:fragment rendered="#{identity.hasPermission('management_group', 'view', group)}">
+ #{group.displayName}:
+ <table cellspacing="5" class="deftable" width="75%">
+ <ui:repeat var="feed" value="#{feedsSecurity.filterViewableFeeds(groupsService.allAcceptedFeeds(group))}">
+ <tr>
+ <td class="term" width="15%">#{feed.name}</td>
+ <td class="def">
+ <ui:repeat var="securityGroup" value="#{securityMod.getFeedAdministratorGroups(feed)}">
+ <li>
+ #{externalSecurityService.getDisplayName(securityGroup)}
+ (
+ <s:link value="delete" action="#{securityMod.deleteSecurityGroup}">
+ <f:param name="role" value="FEED_ADMIN" />
+ <f:param name="feed" value="#{feed.name}" />
+ <f:param name="securityGroup" value="#{securityGroup.externalId}" />
+ </s:link>
+ )
+ </li>
+ </ui:repeat>
+
+ <s:link value="Add user group" view="/security/security_group_add.xhtml">
+ <f:param name="role" value="FEED_ADMIN" />
+ <f:param name="feed" value="#{feed.name}" />
+ </s:link>
+ </td>
+ <td class="def">
+ <ui:repeat var="securityUser" value="#{securityMod.getFeedAdministratorUsers(feed)}">
+ <li>
+ #{externalSecurityService.getDisplayName(securityUser)}
+ (
+ <s:link value="delete" action="#{securityMod.deleteSecurityUser}">
+ <f:param name="role" value="FEED_ADMIN" />
+ <f:param name="feed" value="#{feed.name}" />
+ <f:param name="securityUser" value="#{securityUser.externalId}" />
+ </s:link>
+ )
+ </li>
+ </ui:repeat>
+
+ <s:link value="Add user" view="/security/security_user_add.xhtml">
+ <f:param name="role" value="FEED_ADMIN" />
+ <f:param name="feed" value="#{feed.name}" />
+ </s:link>
+ </td>
+ </tr>
+ </ui:repeat>
+ </table>
+ </s:fragment>
+</ui:repeat>
+
+<h3>Feed viewers:</h3>
+
+<ui:repeat var="group" value="#{groupsService.allGroups}">
+ <s:fragment rendered="#{identity.hasPermission('management_group', 'view', group)}">
+ #{group.displayName}:
+ <table cellspacing="5" class="deftable" width="75%">
+ <ui:repeat var="feed" value="#{groupsService.restrictedFeeds(group)}">
+ <s:fragment rendered="#{identity.hasPermission('feed', 'view', feed)}">
+ <tr>
+ <td class="term" width="15%">#{feed.name}</td>
+ <td class="def">
+ <ui:repeat var="securityGroup" value="#{securityMod.getFeedViewersGroups(feed)}">
+ <li>
+ #{externalSecurityService.getDisplayName(securityGroup)}
+ (
+ <s:link value="delete" action="#{securityMod.deleteSecurityGroup}">
+ <f:param name="role" value="VIEW" />
+ <f:param name="feed" value="#{feed.name}" />
+ <f:param name="securityGroup" value="#{securityGroup.externalId}" />
+ </s:link>
+ )
+ </li>
+ </ui:repeat>
+
+ <s:link value="Add user group" view="/security/security_group_add.xhtml">
+ <f:param name="role" value="VIEW" />
+ <f:param name="feed" value="#{feed.name}" />
+ </s:link>
+ </td>
+ <td class="def">
+ <ui:repeat var="securityUser" value="#{securityMod.getFeedViewersUsers(feed)}">
+ <li>
+ #{externalSecurityService.getDisplayName(securityUser)}
+ (
+ <s:link value="delete" action="#{securityMod.deleteSecurityUser}">
+ <f:param name="role" value="VIEW" />
+ <f:param name="feed" value="#{feed.name}" />
+ <f:param name="securityUser" value="#{securityUser.externalId}" />
+ </s:link>
+ )
+ </li>
+ </ui:repeat>
+
+ <s:link value="Add user" view="/security/security_user_add.xhtml">
+ <f:param name="role" value="VIEW" />
+ <f:param name="feed" value="#{feed.name}" />
+ </s:link>
+ </td>
+ </tr>
+ </s:fragment>
+ </ui:repeat>
+ </table>
+ </s:fragment>
+</ui:repeat>
+</ui:define>
+</ui:composition>
Added: feeds100P26/view/security/security_user_add.xhtml
===================================================================
--- feeds100P26/view/security/security_user_add.xhtml (rev 0)
+++ feeds100P26/view/security/security_user_add.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,66 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../layout/template.xhtml">
+ <ui:define name="header">
+ Select user to add:
+ </ui:define>
+ <ui:define name="body">
+ <h:form>
+ <div class="adminforms">
+ Filter: <h:inputText value="#{securityUserSelect.filter}" />
+ <br />
+
+ <div class="formbuttons">
+ <ul>
+ <li>
+ <h:commandButton value="Search" styleClass="submit" action="search">
+ <f:param name="from" value="0" />
+ </h:commandButton>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </h:form>
+
+ <div class="blogFeedNav #{additionalStyle}">
+ <ul>
+ <ui:include src="../common/next_previous_navigation.xhtml">
+ <ui:param name="viewId" value="/security/security_user_add.xhtml" />
+ <ui:param name="navigationBean" value="#{securityUserSelect}" />
+ <ui:param name="showColon" value="false" />
+ </ui:include>
+ </ul>
+ </div>
+
+ <h:form>
+ <div class="adminforms">
+ <br />
+ <h:panelGrid columns="1">
+ <h:selectOneListbox required="true" value="#{securityMod.restrictedSecurityUser}"
+ converter="securityUserConverter">
+ <s:selectItems var="user" value="#{securityUserSelect.users}"
+ label="#{externalSecurityService.getDisplayName(user)}" />
+ </h:selectOneListbox>
+ </h:panelGrid>
+
+ <div class="formbuttons">
+ <ul>
+ <li>
+ <h:commandButton value="Add" styleClass="submit" action="#{securityMod.addSecurityUser}" />
+ </li>
+ <li>
+ <s:button value="Cancel" view="/security/security_manager.xhtml" styleClass="submit" />
+ </li>
+ </ul>
+ </div>
+ </div>
+ </h:form>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/stylesheet/blog.css
===================================================================
--- feeds100P26/view/stylesheet/blog.css (rev 0)
+++ feeds100P26/view/stylesheet/blog.css 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,496 @@
+.blogFeedNav {
+}
+
+.blogFeedNav_bottom {
+ border: none 0;
+ padding: 0 0 0 10px;
+}
+
+.blogFeedNav_top {
+ border-bottom: 1px solid #8c8f91;
+ padding: 11px 0 5px 10px;
+ margin-bottom: 1em;
+}
+
+.blogFeedNav ul {
+ padding-left: 0;
+ margin-left: 0;
+ display: inline;
+}
+
+.blogFeedNav li {
+ list-style: none;
+ display: inline;
+ padding-right: 6px;
+}
+
+/* MY CHANGES START HERE */
+/* --------------------- =Admin list ------------------------ */
+
+.adminlist {
+ width: 200px;
+ margin-bottom: 0;
+}
+
+.adminlist h3 {
+ font-size:12px;
+ font-weight: bold;
+ margin:9px auto 9px auto;
+}
+
+.adminlist p {
+ margin:0 auto;
+ padding-bottom:1em;
+}
+
+.adminlist dl {
+ margin-right:20px;
+}
+
+.adminlist dt {
+ font-size:12px;
+ font-weight:bold;
+ color:#CC0000;
+ margin:12px 0 1px 0;
+ padding:0;
+}
+
+.adminlist dd {
+ margin:0 0 3px 0;
+}
+
+.adminlist dt a {
+ color:#CC0000;
+ text-decoration:none;
+ background-image:none;
+ padding-left:0;
+}
+
+.adminlist dd a {
+ background-image:url(/file-access/default/theme/images/common/ico_linkarrow_blue.gif);
+ background-repeat: no-repeat;
+ background-position: 3px 3px;
+ padding-left: 12px;
+ white-space:nowrap;
+}
+
+.adminlist hr {
+ border-top:1px dashed #d5d5d5;
+ color: #ffffff;
+ border-bottom:0;
+ border-left:0;
+ border-right:0;
+ margin-bottom:6px;
+}
+
+.adminlinks {
+ float:right;
+ margin-right: 20px;
+ padding-top: 24px;
+}
+
+span.error {
+ color: black;
+ background-color: #fef9e6;
+ border: 1px solid red;
+ padding: 5px;
+ display: block;
+}
+
+span.info {
+ background-color:#FEF9E6;
+ border:1px solid #F9BA82;
+ color:#535353;
+ font-size:10px;
+ display:block;
+ padding:12px;
+}
+
+span.required {
+ color: red;
+}
+
+.bold {
+ font-weight: bold;
+}
+
+.empty {
+
+}
+
+.adminforms .selectwide {
+ width: 400px;
+ margin-bottom: 8px;
+}
+
+.messages {
+
+}
+
+/* =Cheyenne's styles begin here 3/12/08 */
+
+
+.globalOps ul{
+ list-style: none;
+}
+
+.globalOps li{
+ margin: -20px 5px 10px 0px;
+ float: right;
+}
+
+.feedTable .basetablestyle th {
+ height:20px;
+ padding-left: 6px;
+ padding-right: 30px;
+}
+
+.feedheader h4{
+ color: #FFFFFF;
+ font-size:14px;
+ margin: 5px 0px 5px 3px;
+ padding:10px 0px 0px 0px;
+}
+
+.feedTable{
+ margin: 25px 0px 15px 0px;
+}
+
+.feedTable .mainHeader2 {
+ float:left;
+}
+
+.feedTable .formbuttons {
+ float:right;
+}
+
+
+.feedOps {
+ background-color:#FFFFFF;
+}
+
+.newFeed {
+ font-size: 10px;
+ font-weight: bold;
+ background-color: #4a5d75;
+ border-top: 1px solid #94aebd;
+ border-left: 1px solid #94aebd;
+ border-right: 1px solid #233345;
+ border-bottom: 1px solid #233345;
+ height:15px;
+ padding:5px 10px 0px 10px;
+ color: #CC3333;
+ float:right;
+ margin: 10px -24px 0px 1px;
+}
+
+.newFeed a{
+ color: #FFFFFF;
+ text-decoration: none;
+}
+
+.newGroup {
+ font-size: 10px;
+ font-weight: bold;
+ color: #FFFFFF;
+ background-color: #4a5d75;
+ border-top: 1px solid #94aebd;
+ border-left: 1px solid #94aebd;
+ border-right: 1px solid #233345;
+ border-bottom: 1px solid #233345;
+ height:15px;
+ padding:5px 10px 0px 10px;
+ float:right;
+ margin: 10px 5px 0px -10px;
+
+}
+
+.newGroup a{
+ color: #FFFFFF;
+ text-decoration: none;
+}
+
+.rowline select {
+ width: 120px;
+}
+
+/* Archive List css from blog_styles.css */
+
+.blogRightsidebox {
+ padding: 20px;
+ float:right;
+ width:200px;
+}
+
+.blogRightsidebox h4 {
+ font-size:11px;
+ font-weight:bold;
+ padding-left:10px;
+ padding-bottom: 5px;
+ border-bottom: 1px solid #8c8f91;
+}
+
+.blogRightsidebox ul {
+ padding-left: 10px;
+ margin-left: 0px;
+}
+
+.blogRightsidebox li {
+ list-style: none;
+ display: block;
+ padding:.25em 0px;
+}
+
+/* Homepage css */
+
+#columnleftBLOG {
+ float:left;
+ margin: 10px;
+ width:680px;
+}
+
+#columnleftBLOG h4{
+ color: #cc0000;
+ padding: 0px;
+ margin: 0px;
+}
+
+#columnrightBLOG {
+ float:right;
+ width: 225px;
+}
+
+#columnrightBLOG img{
+ border: none;
+ margin-bottom:10px;
+
+}
+
+.laundrytable {
+ width: 680px;
+ text-align: left;
+ line-height: 150%;
+ margin: 0px 0px 20px 20px;
+}
+
+.laundrytable th {
+ vertical-align: top;
+ padding: 0px 5px 0px 0px;
+ font-weight: bold;
+}
+
+.laundrytable td {
+ vertical-align: top;
+ padding: 0px 5px 5px 0px;
+ color: #000000;
+ border-bottom-color: #e1e1e1;
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
+
+}
+
+/* Homepage: Right column - Blog Subnav */
+
+.TwoColumnBlogSubnav {
+ float: right;
+ border: 1px solid #94aebd;
+ background-color: #e1eef4;
+ background-image:url(/file-access/default/theme/images/common/hdr_feed_gradient.gif);
+ background-repeat: repeat-x;
+ background-position:top;
+ padding:0px 12px 12px 11px;
+ margin:0 0 10px 0;
+ width:200px;
+}
+
+.TwoColumnBlogSubnav h4{
+ margin: 0;
+ padding: 0;
+}
+
+.TwoColumnBlogSubnav dt{
+ font-weight:bold;
+ font-size: 14px;
+ color: white;
+ padding:6px 0px 12px 0px;
+ margin:0px;
+}
+.TwoColumnBlogSubnav dd {
+ background-image:url(/file-access/default/theme/images/common/ico_linkarrow_blue.gif);
+ color: #233446;
+ background-repeat: no-repeat;
+ background-position: 0px 3px;
+ padding:0 0 6px 15px;
+ margin:0px;
+}
+
+.TwoColumnBlogSubnav ul {
+ margin: 0px;
+ padding:0px;
+}
+
+.TwoColumnBlogSubnav li {
+ margin: 0;
+ padding: 10px 10px 10px 10px;
+ border-bottom: 1px solid #000000;
+ list-style: none;
+}
+
+.TwoColumnBlogSubnav li.last {
+ border-bottom: none;
+}
+
+
+/* Homepage: Right column - Blog Jelly Box */
+#TwoColumnBlogJelly {
+ float: right;
+ background-repeat:no-repeat;
+ background-position:top;
+ margin-bottom:10px;
+}
+
+
+/* Edit feeds page - additions to Admin List */
+
+.TwoColumnBlogSubnav h4 {
+ font-weight:bold;
+ font-size: 14px;
+ color: white;
+ padding:6px 0px 12px 0px;
+}
+
+hr.formSeparator {
+ margin: 10px 23px 25px auto;
+ border-top: 1px solid #d7d9d9;
+}
+
+.adminforms .checkbox{
+ margin-left:170px;
+}
+
+.submit_first {
+ font-size: 10px;
+ font-weight: bold;
+ color: #FFFFFF;
+ background-color: #e3a835;
+ border-top: 1px solid #fbdea4;
+ border-left: 1px solid #fbdea4;
+ border-right: 1px solid #976c18;
+ border-bottom: 1px solid #976c18;
+ height:20px;
+}
+
+span.instructional_text p {
+ background-color: #f6f6f6;
+ color:#535353;
+ font-size: 10px;
+ padding: 12px;
+ margin: 0px 0 10px 0;
+}
+
+/* Feeds Pages: Right column - Subnav list */
+
+.feedsRightsidebox {
+ padding: 0px 20px 20px 40px;
+ float:right;
+ width:260px;
+ height:100%;
+}
+
+.feedsRightsidebox img{
+ margin:0px 0px 15px 10px;
+ border: 0;
+}
+
+.feedsRightsidebox h4 {
+ font-size:11px;
+ font-weight:bold;
+ padding:3px 0px 3px 10px;
+ margin:10px 10px -10px 0px;
+ border-bottom: 1px solid #8c8f91;
+}
+
+.feedsRightsidebox ul {
+ padding-left: 13px;
+}
+
+.feedsRightsidebox li {
+ list-style:none;
+ padding:.25em 0px;
+}
+
+#feeds_subnav {
+ margin:0px 0 10px 10px;
+ padding:0px;
+}
+
+#feeds_subnav li{
+ background-image:url(/file-access/default/theme/images/common/ico_linkarrow_blue.gif);
+ padding:0px 0 6px 10px;
+ background-repeat: no-repeat;
+ background-position: 0px 3px;
+ font-size: 11px;
+ color: #333366;
+ margin:0px 0px 0px -10px;
+ list-style: none;
+}
+
+.feedsContent {
+/* spacing for when the archive is added margin: 0px 230px 0px 15px; */
+ margin: 0px 325px 0px 15px;
+ padding: 0px;
+}
+
+.feedsContent p {
+ margin: .5em auto;
+ padding: 0px;
+}
+
+#feedstblogentry {
+ margin-top: 0px;
+ border-top: 0px;
+}
+
+.feedsContent h3 {
+ margin: auto auto 0 auto;
+ padding: 0;
+ line-height:2em;
+}
+
+.feedsContent hr {
+ border: none 0;
+ border-top: 1px solid #8c8f91;
+ height: 1px;
+ margin-bottom: 1em;
+}
+
+.feedsContent .blogauthortag {
+ margin:0px Auto;
+ padding-bottom: .5em;
+ font-size:10px;
+ font-weight:normal;
+}
+
+.feedsContent .blogcategorytag {
+ margin:2em Auto 1.5em Auto;
+ padding:0px;
+ font-size:10px;
+ font-weight:normal;
+}
+
+.feedsContent .blogcommentsheader {
+ margin: 1.5em auto 0px auto;
+ padding: 0px;
+ line-height:2em;
+ border-top: 1px dotted #a5a5a5;
+ background-color:#FFFFFF;
+ font-size:11px;
+ font-weight:bold;
+}
+
+.feedsContent .blogcommentsbody {
+ margin: 0px auto 1em auto;
+ padding-bottom: 6px;
+ border-bottom: 1px dashed #d5d5d5;
+ background-color:#FFFFFF;
+}
Added: feeds100P26/view/stylesheet/org_layout.css
===================================================================
--- feeds100P26/view/stylesheet/org_layout.css (rev 0)
+++ feeds100P26/view/stylesheet/org_layout.css 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,84 @@
+/********** org layout: Knowledge Base, Contribute, My.ORG **********/
+
+#ContentTable {
+ width: 960px;
+}
+
+.orgportlet-column {
+ vertical-align: top;
+}
+
+#ORGSubContent {
+ padding-left: 6px;
+ padding-right: 6px;
+ padding-bottom: 6px;
+}
+
+#orgtriple {
+ width: 960px;
+ font-size: 0px;
+ padding-left: 6px;
+ padding-right: 6px;
+ padding-top: 6px;
+}
+
+#orgleft {
+
+}
+
+#orgright {
+
+}
+
+#left1_6 {
+ float:left;
+ padding: 0px 25px 15px 10px;
+ width: 175px;
+}
+
+#center5_6 {
+ float: left;
+ width: 755px;
+}
+
+#orgmaximized {
+ width: 960px;
+}
+
+/* Home maximized */
+
+#orghomemaximized {
+ padding: 10px 15px 10px 10px;
+}
+
+/* Project details */
+
+.orgprojectdetail-innerleft {
+ vertical-align: top;
+ /*width: 260px;*/
+ width: 390px;
+}
+
+/*.orgprojectdetail-innerright {
+ vertical-align: top;
+ width: 260px;
+}*/
+
+.orgprojectdetail-right {
+ vertical-align: top;
+ /*width: 260px;*/
+ width: 390px;
+}
+
+#orgprojectdetailsleft{
+}
+
+#orgprojectdetailscenter {
+}
+
+/* Project details maximized */
+
+#orgprojectdetailsmaximized {
+ padding: 10px 15px 10px 10px;
+}
+
Added: feeds100P26/view/stylesheet/org_main.css
===================================================================
--- feeds100P26/view/stylesheet/org_main.css (rev 0)
+++ feeds100P26/view/stylesheet/org_main.css 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,1060 @@
+body {
+ margin: 0px;
+ padding: 0px;
+ text-align: center;
+ background-color:#e6e7e8;
+ background-image:url(http://labs.jboss.com/file-access/default/theme/images/common/bkgheader_left.gif);
+ background-repeat:repeat-x;
+ font-family: 'Lucida Grande', Geneva, Verdana, Arial, sans-serif;
+ font-size:11px;
+}
+
+#container {
+ margin: 0px auto;
+ width: 969px;
+ text-align: left;
+}
+
+#ORGheader {
+ margin: 0px auto;
+ width: 974px;
+ height:65px;
+ background-image:url(http://labs.jboss.com/file-access/default/theme/images/common/bkgheader_noleft.gif);
+ background-repeat:repeat-x;
+ background-color:#3b4f66;
+}
+
+#contentcontainer {
+ clear:both;
+ margin: 0px auto;
+ background-color:#FFFFFF;
+ background-image:url(http://labs.jboss.com/file-access/default/theme/images/common/bkgblur_right.gif);
+ background-repeat:repeat-y;
+ background-position:right;
+ width: 980px;
+ text-align: left;
+}
+
+#ORGLogo {
+ float:left;
+}
+
+/* --------------------- common elements -------------------------------------------- */
+a {
+ color:#4a5d75;
+}
+
+.clear { clear:both;}
+
+.floatright {
+ float:right;
+}
+.floatleft {
+ float:left;
+}
+
+#majorsectiontitle{
+ background-image:url(http://labs.jboss.com/file-access/default/theme/images/common/hdr_border_gradient.gif);
+ background-repeat:repeat-x;
+ background-position:bottom;
+ color: #CC0000;
+ font-size:16px;
+ margin: 0px 7px 20px 0px;
+ padding:20px 0px 10px 15px;
+}
+
+.nomargin {
+ margin: 0px;
+}
+
+.greyHR {
+ border-top:1px solid #a1a1a1;
+ background-color:#ffffff;
+ border-bottom:0px;
+ border-left:0px;
+ border-right:0px;
+}
+.dashedHR {
+ border-top: 1px dashed #d5d5d5;
+ border-bottom: 0px;
+ border-left: 0px;
+ border-right: 0px;
+}
+
+/* ---------------- Multicolumn layout and specs ----------------------------------- */
+
+
+#ORGContent {
+}
+
+
+/* ---------------- Primary Navigation (Tabbed Nav) ---------------------------- */
+
+#primarynav {
+ clear:right;
+ float:right;
+ margin-top:14px;
+}
+
+#primarynav ul {
+ margin: 0px;
+ padding:0px;
+}
+
+#primarynav ul li {
+ display: inline;
+ list-style: none;
+ text-align:center;
+ float:left;
+ background-image: url(http://labs.jboss.com/file-access/default/theme/images/common/navtabsbkg_norm.gif);
+ background-repeat: repeat-x;
+ background-position: right top;
+
+}
+
+#primarynav ul a {
+ display: inline;
+ float: left;
+ text-decoration: none;
+ font-size:12px;
+ font-weight:bold;
+ color: white;
+ padding: 5px 20px 3px 20px;
+ background-repeat: no-repeat;
+ background-position: top left;
+ border:1px solid #4a5d75;
+
+}
+
+#primarynav ul a:hover {
+ text-decoration: underline;
+ color: white;
+ background-image: url(http://labs.jboss.com/file-access/default/theme/images/common/navtabsbkg_hover.gif);
+ background-repeat: repeat-x;
+ background-position: top left;
+}
+
+#primarynav #current {
+ font-size: 12px;
+ font-weight: bold;
+}
+
+#primarynav #current a, #primarynav a:hover {
+ background-image:none;
+ background-color: white;
+ color: #636464;
+
+}
+
+/* -------- Utility Navigation -------------------- */
+
+#utilitynav {
+ padding-top:6px;
+ height:20px;
+}
+
+#utilitynav ul {
+ float: right;
+ margin:0px;
+ padding: 0px;
+ font-size: 10px;
+ color: #8c8f91;
+}
+
+#utilitynav li {
+ display: inline;
+ list-style: none;
+}
+
+#utilitynav li a {
+ font-weight:bold;
+ color: #FFFFFF;
+}
+
+#utilitynav input {
+ padding:0px;
+ vertical-align:middle;
+}
+
+/* ----------------------- subheadnavigaton ----------------- */
+/* this navigation is used inside a page where a "tabbed" approach is necessary. */
+.subheadnavigaton {
+ margin: 0px 20px;
+ border-bottom: 1px solid #a1a1a1;
+ text-align:right;
+}
+
+.subheadnavigaton ul {
+ margin-bottom: 4px;
+}
+
+.subheadnavigaton li {
+ display:inline;
+ color: #656565;
+ font-size:11px;
+ font-weight:bold;
+}
+
+.subheadnavigaton a {
+ color:#4a5d75;
+}
+
+
+/* -------------------- Footer ---------------------------- */
+.footer {
+ clear:both;
+ text-align:center;
+ color:#a1a1a1;
+ font-size:10px;
+ background-image:url(http://labs.jboss.com/file-access/default/theme/images/common/bkgblur_bottom.gif);
+ background-repeat:no-repeat;
+ background-position:top center;
+ background-color:#e6e7e8;
+ padding:6px 0px;
+
+}
+.footer a {
+ color:#a1a1a1;
+}
+.footer p {
+ margin:0px;
+ padding:1px;
+}
+
+/* ----------------------- Home Page Specific Styles ------------------------- */
+
+
+#columnleftHOME {
+ float: left;
+ padding-left: 12px;
+ width:646px;
+}
+
+#columnrightHOME {
+ float:left;
+ background-image:url(http://labs.jboss.com/file-access/default/theme/images/common/bkg_home_2ndcol.gif);
+ background-repeat:repeat-y;
+ background-position:right;
+}
+
+.knowledgebaseHome {
+ margin:0px;
+ padding:0px;
+ font-size:12px;
+}
+
+.knowledgebaseHome h3 {
+ font-size:16px;
+ font-weight:bold;
+ color:#CC0000;
+ margin:15px 0px 5px 0px;
+ padding:0px;
+}
+.knowledgebaseHome hr {
+ border-top:1px solid #a1a1a1;
+ background-color:#ffffff;
+ border-bottom:0px;
+ border-left:0px;
+ border-right:0px;
+}
+
+.homespot {
+ border: 1px solid #94aebd;
+ background-color: #e1eef4;
+ background-image:url(http://labs.jboss.com/file-access/default/theme/images/common/portlethdr_home.gif);
+ background-repeat:repeat-x;
+ background-position:top;
+ padding:0px 12px 12px 12px;
+ margin:10px;
+ width:265px;
+}
+
+.homespot h3 {
+ font-weight:bold;
+ font-size: 14px;
+ color: white;
+ margin: 0px;
+ padding:6px 0px;
+}
+.homespot h4 {
+ font-weight:bold;
+ font-size: 12px;
+ margin: 0px;
+ padding-top: 6px;
+}
+
+.homespot hr {
+ border-top:1px dashed #94aebd;
+ color: #e1eef4;
+ border-bottom:0px;
+ border-left:0px;
+ border-right:0px;
+}
+
+.homespot p { margin: 3px;}
+
+.homeOrgAnnounce {
+ border: 1px solid #655050;
+ background-color: #faf8ed;
+ background-image:url(http://labs.jboss.com/file-access/default/theme/images/common/portlethdr_homeAnnounce.gif);
+ background-repeat: repeat-x;
+ background-position:top;
+ padding:0px 12px 12px 12px;
+ font-size: 12px;
+ margin:10px;
+ width:265px;
+}
+
+.homeOrgAnnounce h3 {
+ font-weight:bold;
+ font-size: 14px;
+ color: white;
+ margin: 0px;
+ padding:6px 0px;
+}
+.homeOrgAnnounce h4 {
+ font-weight:bold;
+ font-size: 12px;
+ margin: 0px;
+ padding-top: 6px;
+}
+
+.homeOrgAnnounce hr {
+ border-top:1px dashed #655050;
+ color: #faf8ed;
+ border-bottom:0px;
+ border-left:0px;
+ border-right:0px;
+}
+
+.homeOrgAnnounce p {
+ margin: 3px;
+ padding: 6px 0px 3px 0px;
+}
+
+
+.podcast{
+ border:1px solid #646666;
+ margin-top: 12px;
+}
+.podcastfeed { margin: 0px; padding-right: 0px; padding-top:6px;}
+
+.podcastfeed img {
+ border:1px solid #94aebd;
+ vertical-align:middle;
+}
+
+/* --------------------- Projects Main Page Specific Styles : 3 Column layout ------------------------ */
+
+.projectsmainlayout {
+ margin:15px;}
+
+.projectsmainlayout h3 {
+ font-size:12px;
+ font-weight: bold;
+ margin:9px auto 9px auto;
+}
+.projectsmainlayout p {
+ margin:0px auto;
+ padding-bottom:1em;
+ }
+
+.projectsmainlayout dl {
+ margin-right:20px;
+}
+
+.projectsmainlayout dt {
+ font-size:12px;
+ font-weight:bold;
+ color:#CC0000;
+ margin:12px 0px 1px 0px;
+ padding:0px;
+}
+
+.projectsmainlayout dd {
+ margin:0px 0px 3px 0px;
+}
+.projectsmainlayout dt a {
+ color:#CC0000;
+ text-decoration:none;
+ background-image:none;
+ padding-left:0px;
+}
+
+.projectsmainlayout dd a {
+ background-image:url(http://labs.jboss.com/file-access/default/theme/images/common/ico_linkarrow_blue.gif);
+ background-repeat: no-repeat;
+ background-position: 3px 3px;
+ padding-left: 12px;
+ white-space:nowrap;
+}
+.projectsmainlayout hr {
+ margin:0px 0px 3px 0px;
+ border-top:1px dashed #d5d5d5;
+ color: #ffffff;
+ border-bottom:0px;
+ border-left:0px;
+ border-right:0px;
+ margin-bottom:6px;
+}
+
+.projectsmainlayout .projectsmaintextcol {
+ padding-right:30px;
+}
+
+
+.projectsmainlinkcol {
+ width:200px;
+}
+
+/* ----------------------- Base Single Column layout ---------------------------------- */
+
+
+.OneColumnContent {
+ margin: 0px 20px 15px 20px;
+}
+.OneColumnContent h1 {
+ font-size:14px;
+ font-weight: bold;
+}
+.OneColumnContent h2 {
+ font-size:13px;
+ font-weight: bold;
+}
+.OneColumnContent h3 {
+ font-size:12px;
+ font-weight: bold;
+}
+
+/* ----------------------- Project Two Column ---------------------------------- */
+
+
+.TwoColumnContent {
+ padding: 0px 25px 15px 200px;
+}
+
+.TwoColumnContent h1 {
+ font-size:14px;
+ font-weight: bold;
+}
+
+.TwoColumnContent h2 {
+ font-size:13px;
+ font-weight: bold;
+}
+.TwoColumnContent h3 {
+ font-size:12px;
+ font-weight: bold;
+}
+
+
+/* ------------------ Sub Navigation style ---------------------------------------- */
+
+.TwoColumnSubnav {
+ float:left;
+ padding: 0px 0px 15px 10px;
+ /*padding: 0px;*/
+ width: 175px;
+ /*margin: 0px 0px 0px 10px;*/
+}
+
+.TwoColumnSubnav dl {
+ background-color:#b9cae1;
+ margin-top: 0px;
+ margin-bottom:10px;
+}
+
+.TwoColumnSubnav dt {
+ background-color:#3b4e64;
+ padding:5px 0px;
+}
+
+.TwoColumnSubnav dt a {
+ color:#FFFFFF;
+ font-weight:bold;
+ text-decoration:none;
+ background-image:none;
+ margin-left:10px;
+}
+
+.TwoColumnSubnav dd {
+ margin-left:0px;
+ padding:3px 0px 5px 5px;
+}
+
+.TwoColumnSubnav dd a {
+ background-image:url(http://labs.jboss.com/file-access/default/theme/images/common/ico_linkarrow_blue.gif);
+ color: #233446;
+ background-repeat: no-repeat;
+ background-position: 3px 3px;
+ padding-left: 12px;
+}
+
+.TwoColumnSubnav ul {
+ width: 155px;
+ list-style: none;
+ padding-left: 0px;
+ margin-left: 0px;
+ display: block;
+}
+
+.TwoColumnSubnav ul li {
+ list-style: none;
+ display: block;
+ padding: 5px 10px 2px 10px;
+ text-indent: -12px;
+}
+
+
+/* ------------------- Forms ------------------------------- */
+
+.adminforms {
+ margin:0px 20px 10px 20px;
+}
+
+.adminforms h4 {
+ font-weight:bold;
+ font-size:12px;
+ margin:20px auto 20px auto;
+ border-bottom:1px solid #e6e7e8;
+}
+
+.adminforms label{
+ float: left;
+ margin: 0px auto 3px auto;
+ padding-right:10px;
+ white-space:nowrap;
+}
+
+.adminforms input, textarea, select {
+ margin-bottom: 8px;
+}
+
+.adminforms .radios {
+ width: 14px;
+ margin-bottom: -1px;
+}
+.adminforms .selectnarrow {
+ width:80px;
+ margin-bottom: 8px;
+}
+.adminforms .selectmedium {
+ width:160px;
+ margin-bottom: 8px;
+}
+
+.adminforms br {
+ clear: both;
+}
+
+.adminforms hr {
+ border-top:1px dashed #d5d5d5;
+ border-bottom:0px;
+ color: #ffffff;
+ border-left:0px;
+ border-right:0px;
+}
+
+/* -------------------- Buttons ------------------------------ */
+
+.adminforms .submit {
+ font-size: 10px;
+ font-weight: bold;
+ color: #FFFFFF;
+ background-color: #4a5d75;
+ border-top: 1px solid #94aebd;
+ border-left: 1px solid #94aebd;
+ border-right: 1px solid #233345;
+ border-bottom: 1px solid #233345;
+ height:20px;
+ padding:0px 10px 0px 10px;
+}
+
+.formbuttons {
+ margin: 10px auto 15px auto;
+ padding-top: 5px ;
+ border-top: 1px solid #4a5d75;
+}
+
+.formbuttons ul {
+ padding-left: 0px;
+ margin-left: 0px;
+ display: inline;
+}
+
+.formbuttons ul li {
+ list-style: none;
+ display: inline;
+ padding-right: 4px;
+}
+
+.formbuttons .submit {
+ font-size: 10px;
+ font-weight: bold;
+ color: #FFFFFF;
+ background-color: #4a5d75;
+ border-top: 1px solid #94aebd;
+ border-left: 1px solid #94aebd;
+ border-right: 1px solid #233345;
+ border-bottom: 1px solid #233345;
+ height:20px;
+}
+
+.singlecolumn .submit {
+ width:80px;
+}
+.singlecolumn label {
+ width: 170px;
+}
+
+.singlecolumn input, select {
+ width: 300px;
+}
+.adminforms .contentarrows ul {
+ padding-left: 0px;
+ margin-left: 0px;
+ display: block;
+}
+
+.adminforms .contentarrows ul li {
+ list-style: none;
+ display: block;
+ padding: 0px 16px 6px 16px;
+ margin-top: 30px;
+
+}
+.adminforms .contentarrows ul li.last {
+ margin-top: 0px;
+}
+
+#propertiesbox {
+ margin-top: 20px;
+ padding: 0px 10px 10px 10px;
+ background-color: #ececec;
+ border: 1px solid #d5d5d5;
+}
+
+/* -------------------- Info table Style --------------------------------------- */
+
+.basetablestyle, .bodyTable {
+ margin:0px;
+}
+
+.basetablestyle img {
+ border:0px;
+}
+
+.basetablestyle td {
+ height:3em;
+ padding-left: 6px;
+ padding-right: 30px;
+}
+
+.basetablestyle .header {
+ background-color: #233345;
+ font-size:10px;
+ font-weight:bold;
+ color:#94aebd;
+ text-align:left;
+}
+
+.basetablestyle .header a {
+ color:#94aebd;
+}
+
+.basetablestyle .tableheaderfirst {
+ border-bottom:1px solid #233345;
+ height:2em;
+}
+
+.basetablestyle .tableheader {
+ border-left:1px solid #94aebd;
+ border-bottom:1px solid #233345;
+ height:2em;
+}
+
+.basetablestyle .subheader {
+ background-color: #e6e7e8;
+ font-size:10px;
+ font-weight:bold;
+ color:#000000;
+ text-align:left;
+}
+
+.basetablestyle .subheader .tableheaderfirst {
+ height:2em;
+ border-bottom: 0px;
+}
+
+.basetablestyle .subheader .tableheader {
+ height:2em;
+ border-left:1px solid #e6e7e8;
+ border-bottom:0px;
+}
+
+
+
+
+.basetablestyle .rowlinefirst {
+ border-bottom:1px solid #e6e7e8;
+}
+
+.basetablestyle .rowline {
+ border-left:1px solid #e6e7e8;
+ border-bottom:1px solid #e6e7e8;
+}
+
+.basetablestyle .categoryRow {
+ background-color: #dcdedf;
+ font-weight:bold;
+ padding-left: 6px;
+}
+
+.basetablestyle .oddRow, .a {
+ background-color: #f4f3f3;
+ padding-left: 6px;
+}
+
+.basetablestyle .evenRow, .b {
+ background-color: #ffffff;
+}
+
+.basetablestyle .footerrow {
+ background-color:#656565;
+}
+
+.basetablestyle .bottomline {
+ border-bottom:1px solid #656565;
+}
+
+.basetablestyle .topline {
+ border-top:1px solid #656565;
+}
+
+/* ------------------------------------ Project Definitions -------------------------------------- */
+
+.deftable {
+ width: 100%;
+ text-align: left;
+ line-height: 150%;
+ margin-bottom:20px;
+}
+
+.deftable .term {
+ border-top: 1px dotted #cccccc;
+ vertical-align: top;
+ padding: 10px;
+ background-color: #f8f9fb;
+ color: #cc0000;
+ font-weight: bold;
+}
+
+.deftable .termFirst {
+ border-top: 1px dotted black;
+ vertical-align: top;
+ padding: 10px;
+ background-color: #f8f9fb;
+ color: #cc0000;
+ font-weight: bold;
+}
+
+.deftable .termLast {
+ border-top: 1px dotted #cccccc;
+ border-bottom: 1px dotted black;
+ vertical-align: top;
+ padding: 10px;
+ background-color: #f8f9fb;
+ color: #cc0000;
+ font-weight: bold;
+}
+.deftable .def {
+ border-top: 1px dotted #cccccc;
+ vertical-align: top;
+ padding: 10px;
+ color: #000000;
+}
+
+.deftable .defFirst {
+ border-top: 1px dotted black;
+ vertical-align: top;
+ padding: 10px;
+ color: #000000;
+}
+
+.deftable .defLast {
+ border-top: 1px dotted #cccccc;
+ border-bottom: 1px dotted black;
+ vertical-align: top;
+ padding: 10px;
+ color: #000000;
+}
+.deftable .def ul {
+ margin-left: 1em;
+ padding-left: 0px;
+ margin-top: 0px;
+ margin-bottom: 0px;
+}
+.deftable .def ol {
+ margin-top: 0px;
+ margin-bottom: 0px;
+}
+
+.standardLinkArrow {
+ background-image:url(http://labs.jboss.com/file-access/default/theme/images/common/ico_linkarrow_blue.gif);
+ background-repeat: no-repeat;
+ background-position: 3px 3px;
+ padding: 2px 0px 2px 12px;
+ white-space:nowrap;
+}
+.standardLinkArrowLeft {
+ background-image:url(http://labs.jboss.com/file-access/default/theme/images/common/ico_linkarrow_left_blue.gif);
+ background-repeat: no-repeat;
+ background-position: 3px 3px;
+ padding: 2px 0px 2px 12px;
+ white-space:nowrap;
+}
+.standardFeedLink {
+ background-image:url(http://labs.jboss.com/file-access/default/theme/images/common/ico_12x_feed.gif);
+ background-repeat: no-repeat;
+ background-position: 0px 3px;
+ padding: 2px 0px 2px 15px;
+ white-space:nowrap;
+}
+
+/* ------------ style for tabled blocks with backgrounds (main Resources page) ----- */
+
+.shadedblocktable {
+ background-color:#f4f3f3;
+ border-spacing: 20px;
+ border:1px solid #e6e7e8;
+}
+/* QUICKSTART BOX: From the project pages -----------------------------------------*/
+
+.QuickstartMargin { margin: 0px 0px 30px 30px; float: right; }
+#QuickStart { width: 225px; background-color:#e6e7e8; background-image:url(http://labs.jboss.com/file-access/default/theme/images/common/proj_QuickStart_header.gif); background-repeat:no-repeat; background-position: 15px 10px; border:1px solid #656565; }
+#QuickStart ul { padding: 5px 15px; margin-top: 30px; }
+#QuickStart ul li { border-bottom: 1px solid #656565; list-style: none; font: 11px Verdana, Helvetica, Arial, sans-serif; font-weight:bold; }
+#QuickStart ul li a { padding: 4px 0px 4px 8px; display: block; text-decoration: none; color: #656565;}
+#QuickStart ul li a:hover { background-color: #f4f3f3; color: #000000; }
+#QuickStart img { padding-bottom: 10px; }
+
+/* ----- Feed links ------ */
+.FeedNav {
+ margin-top: 1em;
+ padding-top: .5em;
+ border-top: 1px solid #8c8f91;
+}
+
+.FeedNav ul {
+ padding-left: 0px;
+ margin-left: 0px;
+ display: inline;
+}
+
+.FeedNav li {
+ list-style: none;
+ display: inline;
+ padding-right: 6px;
+}
+/* -------------------- Login -------------------- */
+
+.logincontainer {
+ border:1px solid #a1a1a1;
+ padding: 20px 20px 10px 20px;
+ margin: 30px auto 200px auto;
+ width:250px;
+}
+
+.logincontainer p {
+ margin: 3px auto;
+}
+.logincontainer h4 {
+ font-weight:normal;
+ font-size: 12px;
+ color:#343434;
+ margin: 0px auto 8px auto;
+}
+.failedlogin {
+ font-weight:bold;
+ font-size: 12px;
+ color:#cc0000;
+ padding-top: 20px;
+}
+
+.buttonMed {
+ font-size: 10px;
+ font-weight: bold;
+ color: #FFFFFF;
+ background-color: #4a5d75;
+ border-top: 1px solid #94aebd;
+ border-left: 1px solid #94aebd;
+ border-right: 1px solid #233345;
+ border-bottom: 1px solid #233345;
+ height: 20px;
+}
+/* --------------------- Code quotation styles ----------------------------- */
+
+.codeQuoteInline {
+ font-family: "Courier New", Courier, monospace;
+ font-size: 10px;
+ padding: auto 6px;
+}
+
+.codeQuoteBlock {
+ background-color:#e6e7e8;
+ font-family: "Courier New", Courier, monospace;
+ font-size:10px;
+ padding:20px;
+ margin: 5px;
+ line-height:150%;
+}
+
+/* ----------------- Podcast transcript styles ----------------------------- */
+
+.podcast_transcript {
+ width: 100%;
+ border-collapse: collapse;
+}
+
+.podcast_transcript th {
+ vertical-align: top;
+ padding: 1ex;
+ border-bottom: 1px dotted #ccc;
+}
+
+.podcast_transcript td {
+ vertical-align: top;
+ padding: 1ex;
+ border-bottom: 1px dotted #ccc;
+ line-height: 1.6em;
+}
+.podcast_transcript .First {
+ border-top: 1px dotted #ccc;
+}
+
+.podcast_transcript .Last {
+ border-bottom: 1px dotted #ccc;
+}
+
+.podcast_transcript .interviewer {
+ background-color: #f9f9f9;
+}
+
+#podcastTranscriptContainer h2 {
+ padding-bottom: 3px;
+ padding-top:0px;
+ margin:0px;
+}
+
+#podcastTranscriptContainer h3 {
+ font-size:13px;
+ padding-bottom: 3px;
+ padding-top:0px;
+ margin:0px;
+}
+
+#podcastTranscriptContainer h4 {
+ font-size:11px;
+ font-weight:normal;
+ padding-top:0px;
+ padding-bottom:3px;
+ margin:0px;
+}
+
+
+/* -------------------------- Maven Specific Support ----------------------------------- */
+
+.section {
+ padding: 4px;
+}
+
+.section dl {
+ margin: 12px;
+}
+.section dt {
+ margin:0px;
+ font-weight: bold;
+}
+.section dd {
+ margin: 0px;
+ padding-top:2px;
+ padding-bottom: 8px;
+}
+
+.source {
+ padding: 12px;
+ margin: 1em 7px 1em 7px;
+}
+.source pre {
+ margin: 0px;
+ padding: 10px;
+ overflow:auto;
+ border: 1px solid gray;
+ }
+
+.bodyTable {
+ margin: 0px;
+ padding: 0px;
+ border-spacing: 0px;
+}
+
+.bodyTable img {
+ border:0px;
+}
+
+.bodyTable td {
+ height:3em;
+ padding-left: 6px;
+ padding-right: 30px;
+}
+
+.bodyTable th {
+ background-color: #233345;
+ font-size:10px;
+ font-weight:bold;
+ color:#94aebd;
+ text-align:left;
+ padding: 3px;
+}
+
+.bodyTable th a {
+ color:#94aebd;
+}
+
+.bodyTable .a {
+ background-color: #ffffff;
+}
+
+.bodyTable .a td {
+ padding-top: 6px;
+ padding-bottom: 6px;
+ border-bottom:1px solid #e6e7e8;
+}
+
+.bodyTable .b {
+ background-color: #f4f3f3;
+}
+
+.bodyTable .b td {
+ padding-top: 6px;
+ padding-bottom: 6px;
+ border-bottom:1px solid #e6e7e8;
+}
+
+/* ---------------------------- Warning and Info Styles --------------------------------- */
+
+.messages_info {
+ margin:0 20px 12px -20px;
+ padding:15px;
+ background-color:#fef9e6;
+ border: 1px solid #f9ba82;
+ list-style:none;
+}
+
+.messages_warn {
+ margin:0 20px 12px -20px;
+ padding:15px;
+ background-color: #CC3333;
+ border: 1px solid #7B1E1E;
+ list-style: none;
+}
\ No newline at end of file
Added: feeds100P26/view/view/feed.xhtml
===================================================================
--- feeds100P26/view/view/feed.xhtml (rev 0)
+++ feeds100P26/view/view/feed.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,51 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../layout/template.xhtml">
+ <ui:define name="additional_headers">
+ <link rel="alternate" type="application/atom+xml"
+ title="Subscribe to an ATOM feed for '#{feedView.feed.title}'!"
+ href="#{linkService.generateFeedLink(feedView.feed, 'ATOM')}" />
+ </ui:define>
+
+ <ui:define name="header">
+ View feed: #{feedView.feed.title}
+ </ui:define>
+
+ <ui:define name="body">
+ <ui:include src="right_box.xhtml">
+ <ui:param name="feed" value="#{feedView.feed}" />
+ <ui:param name="posts" value="#{feedView.posts}" />
+ <ui:param name="posts_count" value="#{feedView.feed.maxPostsOnPage}" />
+ <ui:param name="more_posts" value="#{feedView.showNext || feedView.showPrevious}" />
+ </ui:include>
+
+ <div class="OneColumnContent">
+ <div class="feedsContent">
+ <ui:include src="feed_toolbar.xhtml">
+ <ui:param name="additionalStyle" value="blogFeedNav_top" />
+ </ui:include>
+
+ <a:repeat var="post" value="#{feedView.posts}" rows="#{feedView.feed.maxPostsOnPage}">
+ <a id="#{post.titleAsId}" />
+ <ui:include src="../common/post.xhtml">
+ <ui:param name="post" value="#{post}" />
+ <ui:param name="showSummary" value="false" />
+ <ui:param name="showAddToHighlights" value="true" />
+ <ui:param name="showPostTo" value="true" />
+ </ui:include>
+ </a:repeat>
+
+ <ui:include src="feed_toolbar.xhtml">
+ <ui:param name="additionalStyle" value="blogFeedNav_bottom" />
+ </ui:include>
+ </div>
+ </div>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/view/feed_toolbar.xhtml
===================================================================
--- feeds100P26/view/view/feed_toolbar.xhtml (rev 0)
+++ feeds100P26/view/view/feed_toolbar.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,25 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j">
+ <div class="blogFeedNav #{additionalStyle}">
+ <ul>
+ <ui:include src="../common/next_previous_navigation.xhtml">
+ <ui:param name="viewId" value="/view/feed.xhtml" />
+ <ui:param name="navigationBean" value="#{feedView}" />
+ <ui:param name="showColon" value="true" />
+ </ui:include>
+ <li>
+ Subscribe to this feed:
+ </li>
+ <li>
+ <a class="standardFeedLink" href="#{linkService.generateFeedLink(feedView.feed, 'ATOM')}">ATOM</a>
+ </li>
+ </ul>
+ </div>
+</ui:composition>
\ No newline at end of file
Added: feeds100P26/view/view/post.xhtml
===================================================================
--- feeds100P26/view/view/post.xhtml (rev 0)
+++ feeds100P26/view/view/post.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,50 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j"
+ template="../layout/template.xhtml">
+ <ui:define name="header">
+ View post: #{postView.post.title}
+ </ui:define>
+
+ <ui:define name="body">
+ <ui:include src="right_box.xhtml">
+ <ui:param name="feed" value="#{postView.post.feed}" />
+ </ui:include>
+
+ <div class="OneColumnContent">
+ <div class="feedsContent">
+ <div class="blogFeedNav blogFeedNav_top">
+ <ul>
+ <li>
+ « Back to feed:  
+ <s:link view="/view/feed.xhtml" value="#{postView.post.feed.title}"
+ propagation="none">
+ <f:param name="name" value="#{postView.post.feed.name}"/>
+ </s:link>
+ </li>
+ <s:fragment rendered="#{identity.hasPermission('post', 'delete', post, post.feed, post.feed.group)}">
+ <li>
+ <br />
+ <s:link value="Delete post" action="#{postView.delete}"
+ onclick="if (!confirm('Are you sure you want to delete this post?')) return false" />
+ </li>
+ </s:fragment>
+ </ul>
+ </div>
+
+ <ui:include src="../common/post.xhtml">
+ <ui:param name="post" value="#{post}" />
+ <ui:param name="showSummary" value="false" />
+ <ui:param name="showAddToHighlights" value="true" />
+ <ui:param name="showPostTo" value="true" />
+ </ui:include>
+ </div>
+ </div>
+ </ui:define>
+</ui:composition>
Added: feeds100P26/view/view/right_box.xhtml
===================================================================
--- feeds100P26/view/view/right_box.xhtml (rev 0)
+++ feeds100P26/view/view/right_box.xhtml 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,51 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:s="http://jboss.com/products/seam/taglib"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:rich="http://richfaces.org/rich"
+ xmlns:a="http://richfaces.org/a4j">
+ <div class="feedsRightsidebox">
+ <h4>Navigation</h4>
+ <ul>
+ <li><s:link view="/home.xhtml" value="Feeds home" propagation="none" /></li>
+ </ul>
+
+ <s:div rendered="#{not empty feed.group.header}">
+ <h:outputText value="#{feed.group.header}" escape="false" />
+ </s:div>
+
+ <div id="TwoColumnBlogJelly">
+ <s:link value="" view="/manage/remote/remote_propose.xhtml" propagation="none">
+ <img src="/feeds/images/propose_blog_full.png"
+ alt="Propose a Blog! If you are blogging on a JBoss-related subject, aggregate it in our system!" />
+ </s:link>
+ </div>
+
+ <s:fragment rendered="#{posts != null}">
+ <h4>Posts of this feed on this page</h4>
+ <ul>
+ <a:repeat var="post" value="#{posts}" rows="#{posts_count}">
+ <li><a href="##{post.titleAsId}">#{post.title}</a></li>
+ </a:repeat>
+ <s:fragment rendered="#{more_posts}">
+ <li>(to view more posts, click the next/previous link)</li>
+ </s:fragment>
+ </ul>
+ </s:fragment>
+
+ <h4>Recent posts from all feeds</h4>
+ <ul>
+ <!-- TODO: configure the number of posts -->
+ <ui:repeat var="post" value="#{feedsService.getPosts(0, 10)}">
+ <li>
+ <s:link view="/view/post.xhtml" value="#{post.title}" propagation="none">
+ <f:param name="post" value="#{post.titleAsId}"/>
+ </s:link>
+ </li>
+ </ui:repeat>
+ </ul>
+ </div>
+</ui:composition>
\ No newline at end of file
Added: feeds100P26/view-portlet/feed_not_found.jsp
===================================================================
--- feeds100P26/view-portlet/feed_not_found.jsp (rev 0)
+++ feeds100P26/view-portlet/feed_not_found.jsp 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,11 @@
+<%@ page language="java" %>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
+<%@ taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
+<%@ page isELIgnored ="false" %>
+
+<portlet:defineObjects />
+
+<span class="messages_warn">
+The feed: '${requestScope.feedName}' does not exist.
+</span>
\ No newline at end of file
Added: feeds100P26/view-portlet/view.jsp
===================================================================
--- feeds100P26/view-portlet/view.jsp (rev 0)
+++ feeds100P26/view-portlet/view.jsp 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,71 @@
+<%@ page import="org.jboss.blog.service.LinkService" %>
+<%@ page import="org.jboss.blog.model.feed.Feed" %>
+<%@ page import="org.jboss.blog.model.Post" %>
+<%@ page import="org.jboss.blog.tools.StringTools" %>
+<%@ page import="java.text.SimpleDateFormat" %>
+<%@ page language="java" %>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
+<%@ taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
+<%@ page isELIgnored ="false" %>
+
+<portlet:defineObjects />
+
+<head>
+ <link href="/feeds/stylesheet/blog.css" rel="stylesheet" type="text/css" />
+</head>
+
+<%
+ Feed feed = (Feed) request.getAttribute("feed");
+ LinkService linkService = (LinkService) request.getAttribute("linkService");
+%>
+
+<div>
+ <c:forEach items="${posts}" var="post">
+ <%
+ Post post = (Post) pageContext.getAttribute("post");
+ %>
+
+ <p>
+ <b>
+ <a href="<%= linkService.generatePostLink(post) %>">${post.title}</a>
+ </b>
+ <br />
+
+ <c:if test="${showDate}">
+ <span class="portlet_author_date">
+ Posted on <%= SimpleDateFormat.getDateTimeInstance().format(post.getPublished()) %> by
+ <%= post.getEffectiveAuthor() %>.
+ </span>
+ </c:if>
+
+ <c:if test="${summaryLength > 0}">
+ <br />
+ <br />
+
+ <span>
+ <%= StringTools.createSummary(post.getContent(), (Integer) request.getAttribute("summaryLength")) %>
+ </span>
+
+ <br />
+ <br />
+ </c:if>
+ </p>
+ </c:forEach>
+
+ <div class="blogFeedNav">
+ <ul>
+ <li>
+ <a href="<%= linkService.generateFeedPageLink(feed) %>"
+ class="standardLinkArrow">
+ View full feed
+ </a>
+ </li>
+ <li>
+ <a href="/feeds" class="standardLinkArrow">
+ Go to JBoss.ORG Feeds home
+ </a>
+ </li>
+ </ul>
+ </div>
+</div>
\ No newline at end of file
Added: feeds100P26/view-portlet/view_main.jsp
===================================================================
--- feeds100P26/view-portlet/view_main.jsp (rev 0)
+++ feeds100P26/view-portlet/view_main.jsp 2009-03-26 13:55:24 UTC (rev 350)
@@ -0,0 +1,67 @@
+<%@ page import="org.jboss.blog.service.LinkService" %>
+<%@ page import="org.jboss.blog.model.feed.Feed" %>
+<%@ page import="org.jboss.blog.model.Post" %>
+<%@ page import="org.jboss.blog.tools.StringTools" %>
+<%@ page import="java.text.SimpleDateFormat" %>
+<%@ page language="java" %>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
+<%@ taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
+<%@ page isELIgnored ="false" %>
+
+<portlet:defineObjects />
+
+<head>
+ <link href="/feeds/stylesheet/blog.css" rel="stylesheet" type="text/css" />
+</head>
+
+<%
+ Feed feed = (Feed) request.getAttribute("feed");
+ LinkService linkService = (LinkService) request.getAttribute("linkService");
+%>
+
+<div class="homespot">
+ <h3>Latest Blogs</h3>
+
+ <c:forEach items="${posts}" var="post">
+ <%
+ Post post = (Post) pageContext.getAttribute("post");
+ %>
+
+ <p>
+ <b>
+ <a href="<%= linkService.generatePostLink(post) %>">${post.title}</a>
+ </b>
+ <br />
+
+ <c:if test="${showDate}">
+ <span class="portlet_author_date">
+ Posted on <%= SimpleDateFormat.getDateTimeInstance().format(post.getPublished()) %> by
+ <%= post.getEffectiveAuthor() %>.
+ </span>
+ </c:if>
+
+ <c:if test="${summaryLength > 0}">
+ <span>
+ <%= StringTools.createSummary(post.getContent(), (Integer) request.getAttribute("summaryLength")) %>
+ </span>
+ </c:if>
+ </p>
+ </c:forEach>
+
+ <div class="blogFeedNav">
+ <ul>
+ <li>
+ <a href="<%= linkService.generateFeedPageLink(feed) %>"
+ class="standardLinkArrow">
+ View full feed
+ </a>
+ </li>
+ <li>
+ <a href="/feeds" class="standardLinkArrow">
+ Go to JBoss.ORG Feeds home
+ </a>
+ </li>
+ </ul>
+ </div>
+</div>
\ No newline at end of file
More information about the jboss-cvs-commits
mailing list