package org.atomhopper.config; import org.apache.abdera.model.Feed; import org.apache.abdera.protocol.server.TargetType; import org.apache.abdera.protocol.server.impl.RegexTargetResolver; import org.apache.commons.lang.StringUtils; import org.atomhopper.abdera.FeedAdapter; import org.atomhopper.abdera.TargetAwareAbstractCollectionAdapter; import org.atomhopper.abdera.WorkspaceHandler; import org.atomhopper.abdera.filter.AdapterResponseInterceptor; import org.atomhopper.abdera.filter.FeedEntityTagProcessor; import org.atomhopper.abdera.filter.FeedPagingProcessor; import org.atomhopper.abdera.response.FeedResponseHandler; import org.atomhopper.adapter.FeedPublisher; import org.atomhopper.adapter.FeedSource; import org.atomhopper.config.v1_0.AdapterDescriptor; import org.atomhopper.config.v1_0.FeedConfiguration; import org.atomhopper.config.v1_0.HostConfiguration; import org.atomhopper.config.v1_0.WorkspaceConfiguration; import org.atomhopper.servlet.ApplicationContextAdapter; import org.atomhopper.util.TargetRegexBuilder; import org.atomhopper.util.context.AdapterGetter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; /** * I eat configurations. * * TODO: Sanitize configured workspace and feed resource paths for regex * insertion */ public class WorkspaceConfigProcessor { private static final Logger LOG = LoggerFactory.getLogger(WorkspaceConfigProcessor.class); private final RegexTargetResolver regexTargetResolver; private final AdapterGetter adapterGetter; private final WorkspaceConfiguration config; private final TargetRegexBuilder targetRegexGenerator; private final HostConfiguration hostConfiguration; //TODO: Consider builder pattern public WorkspaceConfigProcessor(WorkspaceConfiguration config, ApplicationContextAdapter contextAdapter, RegexTargetResolver regexTargetResolver, String contextPath, HostConfiguration hostConfiguration ) { this.config = config; this.adapterGetter = new AdapterGetter(contextAdapter); this.regexTargetResolver = regexTargetResolver; targetRegexGenerator = new TargetRegexBuilder(); if (!StringUtils.isBlank(contextPath)) { targetRegexGenerator.setContextPath(contextPath); } this.hostConfiguration = hostConfiguration; } public List<WorkspaceHandler> toHandler() { final List<WorkspaceHandler> workspaces = new LinkedList<WorkspaceHandler>(); for (TargetAwareAbstractCollectionAdapter collectionAdapter : assembleFeeds(config.getFeed())) { final WorkspaceHandler workspace = new WorkspaceHandler(config); workspace.addCollectionAdapter(new StringBuilder() .append(config.getResource()) .append(collectionAdapter .getTarget()).toString(), collectionAdapter); LOG.info("Loading Workspace: " + collectionAdapter.getTarget()); workspaces.add(workspace); } return workspaces; } private List<TargetAwareAbstractCollectionAdapter> assembleFeeds(List<FeedConfiguration> feedServices) { final List<TargetAwareAbstractCollectionAdapter> collections = new LinkedList<TargetAwareAbstractCollectionAdapter>(); final String workspaceName = StringUtils.strip(config.getResource(), "/"); targetRegexGenerator.setWorkspace(workspaceName); // service regexTargetResolver.setPattern(targetRegexGenerator.toWorkspacePattern(), TargetType.TYPE_SERVICE, TargetRegexBuilder.getWorkspaceResolverFieldList()); for (TargetAwareAbstractCollectionAdapter adapter : assembleFeedAdapters(targetRegexGenerator, feedServices)) { collections.add(adapter); } return collections; } public <T> T getFromApplicationContext(String referenceName, String className, Class<T> expectedClass) { T resolvedReference = null; if (!StringUtils.isBlank(referenceName)) { resolvedReference = adapterGetter.getByName(referenceName, expectedClass); } if (resolvedReference == null && !StringUtils.isBlank(className)) { try { resolvedReference = adapterGetter.getByClassDefinition(Class.forName(className), expectedClass); } catch (ClassNotFoundException cnfe) { LOG.error("Unable to find specified default adapter class: " + className, cnfe); throw new ConfigurationException("Unable to find specified default adapter class: " + className, cnfe); } } return resolvedReference; } public <T> T getAdapter(AdapterDescriptor descriptor, Class<T> expectedClass) { return descriptor != null ? getFromApplicationContext(descriptor.getReference(), descriptor.getClazz(), expectedClass) : null; } private List<TargetAwareAbstractCollectionAdapter> assembleFeedAdapters(TargetRegexBuilder workspaceTarget, List<FeedConfiguration> feeds) { final List<TargetAwareAbstractCollectionAdapter> collections = new LinkedList<TargetAwareAbstractCollectionAdapter>(); for (FeedConfiguration feed : feeds) { final FeedSource feedSource = getAdapter(feed.getFeedSource(), FeedSource.class); checkArchiving( feed, feedSource ); final FeedPublisher feedPublisher = getAdapter(feed.getPublisher(), FeedPublisher.class); final TargetRegexBuilder feedTargetRegexBuilder = new TargetRegexBuilder(workspaceTarget); feedTargetRegexBuilder.setFeed(feed.getResource()); List <AdapterResponseInterceptor<Feed>> adapterResponseInterceptorList = new ArrayList<AdapterResponseInterceptor<Feed>>(); if ( feed.getFeedResponseHandlers() != null && feed.getFeedResponseHandlers().getFeedResponseHandler() != null && !feed.getFeedResponseHandlers().getFeedResponseHandler().isEmpty() ) { List<AdapterDescriptor> adapterDescriptorList = feed.getFeedResponseHandlers().getFeedResponseHandler(); for (AdapterDescriptor adapterDescriptor : adapterDescriptorList ) { AdapterResponseInterceptor<Feed> interceptor = (AdapterResponseInterceptor<Feed>) getAdapter(adapterDescriptor, AdapterResponseInterceptor.class); adapterResponseInterceptorList.add(interceptor); } } else { // this was the old list of response interceptors adapterResponseInterceptorList.add(new FeedPagingProcessor()); adapterResponseInterceptorList.add(new FeedEntityTagProcessor()); } final FeedAdapter feedAdapter = new FeedAdapter( feedTargetRegexBuilder.getFeedResource(), feed, feedSource, feedPublisher, adapterResponseInterceptorList); // feed regex matching regexTargetResolver.setPattern(feedTargetRegexBuilder.toFeedPattern(), TargetType.TYPE_COLLECTION, TargetRegexBuilder.getFeedResolverFieldList()); // entry regex matching regexTargetResolver.setPattern(feedTargetRegexBuilder.toEntryPattern(), TargetType.TYPE_ENTRY, TargetRegexBuilder.getEntryResolverFieldList()); collections.add(feedAdapter); } return collections; } /** * From the feed configuration XML, sets the FeedSourced with the following: * <ul> * <li>If the feed is an archive, sets the "current" link URL.</li> * <li>If the feed has a archived feed, sets the next-archive link URL for its last page.</li> * </ul> * * @param feed * @param feedSource */ public void checkArchiving( FeedConfiguration feed, FeedSource feedSource ) { if ( feed.isArchived() && feed.getArchiveFeed() != null ) { LOG.error( "Feed '" + feed.getTitle() + "' cannot be tagged as an archived feed & have an archive-feed declared." ); throw new ConfigurationException( "Feed '" + feed.getTitle() + "' cannot be tagged as an archived feed & have an archive-feed declared.", new RuntimeException() ); } if ( feed.isArchived() && feed.getCurrentFeed() == null ) { LOG.error( "Feed '" + feed.getTitle() + "' cannot be tagged as an archived feed & not have a current-feed declared." ); throw new ConfigurationException( "Feed '" + feed.getTitle() + "' cannot be tagged as an archived feed & not have a current-feed declared.", new RuntimeException() ); } if ( !feed.isArchived() && feed.getCurrentFeed() != null ) { LOG.error( "Feed '" + feed.getTitle() + "' cannot be a non-archived feed & have a current-feed declared." ); throw new ConfigurationException( "Feed '" + feed.getTitle() + "' cannot be a non-archived feed & have a current-feed declared.", new RuntimeException() ); } if ( feed.getCurrentFeed() != null ) { String href = createUrl( feed.getCurrentFeed().getHref() ); try { feedSource.setCurrentUrl( new URL( href ) ); } catch ( MalformedURLException e ) { LOG.error( "Invalid current URL feed '" + feed.getTitle() + "': '" + href + "'" ); throw new ConfigurationException( "Invalid current URL feed '" + feed.getTitle() + "': '" + href + "'", e ); } } if ( feed.getArchiveFeed() != null ) { String href = createUrl( feed.getArchiveFeed().getHref() ); try { feedSource.setArchiveUrl( new URL( href ) ); } catch ( MalformedURLException e ) { LOG.error( "Invalid archive URL feed '" + feed.getTitle() + "': '" + href + "'" ); throw new ConfigurationException( "Invalid archive URL feed '" + feed.getTitle() + "': '" + href + "'", e ); } } } private String createUrl( String href ) { if ( href.startsWith( "/" ) ) { href = hostConfiguration.getScheme() + "://" + hostConfiguration.getDomain() + href; } return href; } }