package org.atomhopper.abdera; import java.util.*; import javax.security.auth.Subject; import org.apache.abdera.Abdera; import org.apache.abdera.protocol.server.*; import org.apache.abdera.protocol.server.context.ResponseContextException; import org.apache.abdera.protocol.server.impl.RegexTargetResolver; import org.apache.abdera.protocol.server.impl.SimpleSubjectResolver; import org.apache.abdera.protocol.server.impl.TemplateTargetBuilder; import org.apache.abdera.protocol.server.processors.CategoriesRequestProcessor; import org.apache.abdera.protocol.server.processors.CollectionRequestProcessor; import org.apache.abdera.protocol.server.processors.EntryRequestProcessor; import org.apache.abdera.protocol.server.processors.ServiceRequestProcessor; import org.atomhopper.config.v1_0.HostConfiguration; import org.atomhopper.util.uri.template.EnumKeyedTemplateParameters; import org.atomhopper.util.uri.template.TemplateParameters; import org.atomhopper.util.uri.template.URITemplate; import org.atomhopper.util.uri.template.URITemplateParameter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class WorkspaceProvider implements Provider { private static final Logger LOG = LoggerFactory.getLogger(WorkspaceProvider.class); private static final int MIN_ERROR_CODE = 400; private static final int MAX_ERROR_CODE = 500; private static final String XML = "application/xml"; private final Map<TargetType, RequestProcessor> requestProcessors; private final List<Filter> filters; private final WorkspaceManager workspaceManager; private final RegexTargetResolver targetResolver; private final HostConfiguration hostConfiguration; private final TemplateTargetBuilder templateTargetBuilder; private Map<String, String> properties; private Abdera abdera; public WorkspaceProvider(HostConfiguration hostConfiguration) { requestProcessors = new HashMap<TargetType, RequestProcessor>(); filters = new LinkedList<Filter>(); targetResolver = new RegexTargetResolver(); // Set the host configuration this.hostConfiguration = hostConfiguration; // Setting default request processors: requestProcessors.put(TargetType.TYPE_SERVICE, new ServiceRequestProcessor()); requestProcessors.put(TargetType.TYPE_CATEGORIES, new CategoriesRequestProcessor()); requestProcessors.put(TargetType.TYPE_COLLECTION, new CollectionRequestProcessor()); requestProcessors.put(TargetType.TYPE_ENTRY, new EntryRequestProcessor()); templateTargetBuilder = new TemplateTargetBuilder(); templateTargetBuilder.setTemplate(URITemplate.WORKSPACE, URITemplate.WORKSPACE.toString()); templateTargetBuilder.setTemplate(URITemplate.FEED, URITemplate.FEED.toString()); workspaceManager = new WorkspaceManager(); } public RegexTargetResolver getTargetResolver() { return targetResolver; } public WorkspaceManager getWorkspaceManager() { return workspaceManager; } @Override public void init(Abdera abdera, Map<String, String> properties) { this.abdera = abdera; this.properties = properties; } @Override public String getProperty(String name) { return properties.get(name); } @Override public String[] getPropertyNames() { return properties.keySet().toArray(new String[properties.size()]); } @Override public Abdera getAbdera() { return abdera; } @Override public Subject resolveSubject(RequestContext request) { return new SimpleSubjectResolver().resolve(request); } @Override public Target resolveTarget(RequestContext request) { return targetResolver.resolve(request); } @Override public String urlFor(RequestContext request, Object key, Object param) { final Target resolvedTarget = request.getTarget(); if (param == null || param instanceof TemplateParameters) { final TemplateParameters templateParameters = param != null ? (TemplateParameters) param : new EnumKeyedTemplateParameters((Enum) key); templateParameters.set(URITemplateParameter.HOST_DOMAIN, hostConfiguration.getDomain()); templateParameters.set(URITemplateParameter.HOST_SCHEME, hostConfiguration.getScheme()); //This is what happens when you don't use enumerations :p if (resolvedTarget.getType() == TargetType.TYPE_SERVICE) { templateParameters.set(URITemplateParameter.WORKSPACE_RESOURCE, resolvedTarget.getParameter(TargetResolverField.WORKSPACE.toString())); } else if (resolvedTarget.getType() == TargetType.TYPE_COLLECTION) { templateParameters.set(URITemplateParameter.WORKSPACE_RESOURCE, resolvedTarget.getParameter(TargetResolverField.WORKSPACE.toString())); templateParameters.set(URITemplateParameter.FEED_RESOURCE, resolvedTarget.getParameter(TargetResolverField.FEED.toString())); } else if (resolvedTarget.getType() == TargetType.TYPE_CATEGORIES) { templateParameters.set(URITemplateParameter.WORKSPACE_RESOURCE, resolvedTarget.getParameter(TargetResolverField.WORKSPACE.toString())); templateParameters.set(URITemplateParameter.FEED_RESOURCE, resolvedTarget.getParameter(TargetResolverField.FEED.toString())); } else if (resolvedTarget.getType() == TargetType.TYPE_ENTRY) { templateParameters.set(URITemplateParameter.WORKSPACE_RESOURCE, resolvedTarget.getParameter(TargetResolverField.WORKSPACE.toString())); templateParameters.set(URITemplateParameter.FEED_RESOURCE, resolvedTarget.getParameter(TargetResolverField.FEED.toString())); templateParameters.set(URITemplateParameter.ENTRY_RESOURCE, resolvedTarget.getParameter(TargetResolverField.ENTRY.toString())); } return templateTargetBuilder.urlFor(request, key, templateParameters.toMap()); } //Support maps eventually for this throw new IllegalArgumentException("URL Generation expects a TemplateParameters object"); } @Override public ResponseContext process(RequestContext request) { final Target target = request.getTarget(); if (target == null || target.getType() == TargetType.TYPE_NOT_FOUND) { return ProviderHelper.notfound(request).setContentType(XML); } final RequestProcessor processor = this.requestProcessors.get(target.getType()); if (processor == null) { return ProviderHelper.notfound(request).setContentType(XML); } final CollectionAdapter adapter = getWorkspaceManager().getCollectionAdapter(request); ResponseContext response = null; if (adapter != null) { final Transactional transaction = adapter instanceof Transactional ? (Transactional) adapter : null; try { transactionStart(transaction, request); response = processor.process(request, workspaceManager, adapter); response = response != null ? response : processExtensionRequest(request, adapter); } catch (Exception ex) { response = handleAdapterException(ex, transaction, request); } finally { transactionEnd(transaction, request, response); } } else { response = ProviderHelper.notfound(request).setContentType(XML); } return response != null ? response : ProviderHelper.badrequest(request).setContentType(XML); } private ResponseContext handleAdapterException(Exception ex, Transactional transaction, RequestContext request) { if (ex instanceof ResponseContextException) { final ResponseContextException rce = (ResponseContextException) ex; if (rce.getStatusCode() >= MIN_ERROR_CODE && rce.getStatusCode() < MAX_ERROR_CODE) { // don't report routine 4xx HTTP errors LOG.info(ex.getMessage(), ex); } else { LOG.error(ex.getMessage(), ex); } } else { LOG.error(ex.getMessage(), ex); } transactionCompensate(transaction, request, ex); return ProviderHelper.servererror(request, ex).setContentType(XML); } private void transactionCompensate(Transactional transactional, RequestContext request, Throwable e) { if (transactional != null) { transactional.compensate(request, e); } } private void transactionEnd(Transactional transactional, RequestContext request, ResponseContext response) { if (transactional != null) { transactional.end(request, response); } } private void transactionStart(Transactional transactional, RequestContext request) throws ResponseContextException { if (transactional != null) { transactional.start(request); } } private ResponseContext processExtensionRequest(RequestContext context, CollectionAdapter adapter) { return adapter.extensionRequest(context); } @Override public Filter[] getFilters(RequestContext request) { return filters.toArray(new Filter[filters.size()]); } public void addFilter(Filter... filters) { this.filters.addAll(Arrays.asList(filters)); } @Override public void setRequestProcessors(Map<TargetType, RequestProcessor> requestProcessors) { this.requestProcessors.clear(); this.requestProcessors.putAll(requestProcessors); } @Override public void addRequestProcessors(Map<TargetType, RequestProcessor> requestProcessors) { this.requestProcessors.putAll(requestProcessors); } @Override public Map<TargetType, RequestProcessor> getRequestProcessors() { return Collections.unmodifiableMap(this.requestProcessors); } }