diff options
author | Roberto E. Escobar | 2014-08-13 02:03:33 +0000 |
---|---|---|
committer | Roberto E. Escobar | 2014-09-29 22:55:18 +0000 |
commit | 436b129e96abc4028393ae3e817cdda4f70e68a1 (patch) | |
tree | 9cacf6d23deb056dbab23ff57f8d44a223ac8a17 /plugins/org.eclipse.osee.jaxrs.server | |
parent | ae55c5a19aa0c72da73ac22756a9df75228528d9 (diff) | |
download | org.eclipse.osee-436b129e96abc4028393ae3e817cdda4f70e68a1.tar.gz org.eclipse.osee-436b129e96abc4028393ae3e817cdda4f70e68a1.tar.xz org.eclipse.osee-436b129e96abc4028393ae3e817cdda4f70e68a1.zip |
feature[ats_ATS99009]: Add static content contributions to JAX-RS
Change-Id: I3111baf46a00965f4c95d192862e2ee5c2cbf2c2
Diffstat (limited to 'plugins/org.eclipse.osee.jaxrs.server')
8 files changed, 496 insertions, 33 deletions
diff --git a/plugins/org.eclipse.osee.jaxrs.server/META-INF/MANIFEST.MF b/plugins/org.eclipse.osee.jaxrs.server/META-INF/MANIFEST.MF index 631e6b8f57a..f7b2df1c5a1 100644 --- a/plugins/org.eclipse.osee.jaxrs.server/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.osee.jaxrs.server/META-INF/MANIFEST.MF @@ -67,6 +67,7 @@ Import-Package: com.google.common.cache, org.eclipse.osee.jaxrs.client, org.eclipse.osee.jaxrs.mvc, org.eclipse.osee.logger, + org.eclipse.osgi.util, org.osgi.framework, org.osgi.service.http Bundle-Vendor: Eclipse Open System Engineering Environment diff --git a/plugins/org.eclipse.osee.jaxrs.server/OSGI-INF/jaxrs.admin.application.xml b/plugins/org.eclipse.osee.jaxrs.server/OSGI-INF/jaxrs.admin.application.xml index 96661993edc..55292a55db5 100644 --- a/plugins/org.eclipse.osee.jaxrs.server/OSGI-INF/jaxrs.admin.application.xml +++ b/plugins/org.eclipse.osee.jaxrs.server/OSGI-INF/jaxrs.admin.application.xml @@ -5,4 +5,5 @@ <provide interface="javax.ws.rs.core.Application"/> </service> <reference bind="setJaxRsApplicationRegistry" cardinality="1..1" interface="org.eclipse.osee.jaxrs.server.internal.applications.JaxRsApplicationRegistry" name="JaxRsApplicationRegistry" policy="static"/> + <reference bind="setJaxRsResourceManager" cardinality="1..1" interface="org.eclipse.osee.jaxrs.server.internal.JaxRsResourceManager" name="JaxRsResourceManager" policy="static"/> </scr:component> diff --git a/plugins/org.eclipse.osee.jaxrs.server/OSGI-INF/jaxrs.resource.manager.xml b/plugins/org.eclipse.osee.jaxrs.server/OSGI-INF/jaxrs.resource.manager.xml new file mode 100644 index 00000000000..de0df916b94 --- /dev/null +++ b/plugins/org.eclipse.osee.jaxrs.server/OSGI-INF/jaxrs.resource.manager.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="start" deactivate="stop"> + <implementation class="org.eclipse.osee.jaxrs.server.internal.JaxRsResourceManager" /> + <reference bind="setLogger" cardinality="1..1" interface="org.eclipse.osee.logger.Log" name="Log" policy="static"/> + <service> + <provide interface="org.eclipse.osee.jaxrs.server.internal.JaxRsResourceManager"/> + </service> +</scr:component> diff --git a/plugins/org.eclipse.osee.jaxrs.server/OSGI-INF/jaxrs.static.resource.filter.xml b/plugins/org.eclipse.osee.jaxrs.server/OSGI-INF/jaxrs.static.resource.filter.xml new file mode 100644 index 00000000000..e87d4d2906a --- /dev/null +++ b/plugins/org.eclipse.osee.jaxrs.server/OSGI-INF/jaxrs.static.resource.filter.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"> + <implementation class="org.eclipse.osee.jaxrs.server.internal.resources.JaxRsStaticResourceRequestFilter" /> + <service> + <provide interface="javax.ws.rs.container.ContainerRequestFilter"/> + <provide interface="java.lang.Object"/> + </service> + <reference bind="setJaxRsResourceManager" cardinality="1..1" interface="org.eclipse.osee.jaxrs.server.internal.JaxRsResourceManager" name="JaxRsResourceManager" policy="static"/> +</scr:component> diff --git a/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/JaxRsAdminApplication.java b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/JaxRsAdminApplication.java index fc86f58318e..83ccc43ea21 100644 --- a/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/JaxRsAdminApplication.java +++ b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/JaxRsAdminApplication.java @@ -26,13 +26,18 @@ public class JaxRsAdminApplication extends Application { private final Set<Object> singletons = new LinkedHashSet<Object>(); private JaxRsApplicationRegistry registry; + private JaxRsResourceManager manager; public void setJaxRsApplicationRegistry(JaxRsApplicationRegistry registry) { this.registry = registry; } + public void setJaxRsResourceManager(JaxRsResourceManager manager) { + this.manager = manager; + } + public void start() { - singletons.add(new JaxRsContributionsResource(registry)); + singletons.add(new JaxRsContributionsResource(registry, manager)); } public void stop() { diff --git a/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/JaxRsResourceManager.java b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/JaxRsResourceManager.java new file mode 100644 index 00000000000..fb3bb59add2 --- /dev/null +++ b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/JaxRsResourceManager.java @@ -0,0 +1,278 @@ +/******************************************************************************* + * Copyright (c) 2014 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.jaxrs.server.internal; + +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import org.eclipse.osee.framework.jdk.core.util.Strings; +import org.eclipse.osee.logger.Log; +import org.eclipse.osgi.util.ManifestElement; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleEvent; +import org.osgi.framework.BundleException; +import org.osgi.framework.BundleListener; + +/** + * Class responsible for managing static web resources contributed by bundles. + * + * <pre> + * Contributions are specified in the bundle's MANIFEST.MF file using the following header and syntax: + * + * <b>Osee-JaxRs-Resource:</b> <i>path_to_resource<i><b>;path=</b><i>web_address</i><b>,</b> ... + * + * Example: + * <b>Osee-JaxRs-Resource:</b> <i>/web/js/*<i><b>;path=</b><i>/lib</i> + * + * Make all files in <b>/web/js/</b> available through <b>/lib/</b>. + * Therefore, if we have a file - /web/js/script.js it will be available at /lib/script.js + * </pre> + * + * @author Roberto E. Escobar + */ +public final class JaxRsResourceManager implements BundleListener { + + public interface JaxRsResourceVisitor { + void onResource(Bundle bundle, Collection<String> resources); + } + + public interface Resource { + + URL getUrl(); + + } + + private static final String OSEE_WEB_RESOURCE_HDR = "Osee-JaxRs-Resource"; + private static final String OSEE_WEB_RESOURCE_HDR__PATH_ATTRIBUTE = "path"; + + private Map<String, Resource> pathToResource; + private Map<Bundle, Set<String>> bundleToKey; + + private Log logger; + + public void setLogger(Log logger) { + this.logger = logger; + } + + public void start(BundleContext context) { + pathToResource = new HashMap<String, Resource>(); + bundleToKey = new HashMap<Bundle, Set<String>>(); + + context.addBundleListener(this); + + // Add bundles that have already started + Bundle[] bundles = context.getBundles(); + if (bundles != null) { + for (Bundle bundle : bundles) { + int state = bundle.getState(); + processBundle(bundle, state); + } + } + } + + public void stop(BundleContext context) { + context.removeBundleListener(this); + + if (pathToResource != null) { + pathToResource.clear(); + pathToResource = null; + } + + if (bundleToKey != null) { + bundleToKey.clear(); + bundleToKey = null; + } + } + + public Resource getResource(String path) { + String toMatch = JaxRsUtils.normalize(path); + return pathToResource.get(toMatch); + } + + public void accept(JaxRsResourceVisitor visitor) { + for (Entry<Bundle, Set<String>> entry : bundleToKey.entrySet()) { + visitor.onResource(entry.getKey(), Collections.unmodifiableCollection(entry.getValue())); + } + } + + @Override + public void bundleChanged(BundleEvent event) { + Bundle bundle = event.getBundle(); + processBundle(bundle, event.getType()); + } + + private String getWebResourceHeader(Bundle bundle) { + return bundle.getHeaders().get(OSEE_WEB_RESOURCE_HDR); + } + + private boolean hasWebResourceHeader(Bundle bundle) { + String headerValue = getWebResourceHeader(bundle); + return Strings.isValid(headerValue); + } + + private void processBundle(Bundle bundle, int state) { + boolean isActive = false; + boolean isStopping = false; + if (state == Bundle.ACTIVE // + || state == Bundle.STARTING // + || state == Bundle.INSTALLED // + || state == Bundle.RESOLVED) { + isActive = true; + } else if (state == Bundle.STOPPING) { + isStopping = true; + } + + if (isActive && hasWebResourceHeader(bundle)) { + addBundle(bundle); + } else if (isStopping && hasWebResourceHeader(bundle)) { + removeBundle(bundle); + } + } + + private void removeBundle(Bundle bundle) { + Set<String> paths = bundleToKey.get(bundle); + if (paths != null && !paths.isEmpty()) { + for (String path : paths) { + pathToResource.remove(path); + } + } + } + + private boolean isValidEntry(Bundle bundle, String headerValue, String resource, String pathAttribute) { + boolean result = false; + if (!Strings.isValid(pathAttribute)) { + logger.warn("Invalid path attribute [%s] for resource [%s] in bundle [%s] with header[%s]", pathAttribute, + resource, bundle.getSymbolicName(), headerValue); + } else if (!Strings.isValid(resource)) { + logger.warn("Invalid resource [%s] for bundle[%s] with header[%s].", resource, bundle.getSymbolicName(), + headerValue); + } else { + result = true; + } + return result; + } + + private void addBundle(Bundle bundle) { + String bundleName = bundle.getSymbolicName(); + String headerValue = getWebResourceHeader(bundle); + + ManifestElement[] elements = null; + try { + elements = ManifestElement.parseHeader(OSEE_WEB_RESOURCE_HDR, headerValue); + } catch (BundleException ex) { + logger.error(ex, "Error parsing manifest header [%s] for bundle [%s]", OSEE_WEB_RESOURCE_HDR, bundleName); + } + + if (elements != null && elements.length > 0) { + for (ManifestElement element : elements) { + String resource = element.getValue(); + String aliasAttribute = element.getAttribute(OSEE_WEB_RESOURCE_HDR__PATH_ATTRIBUTE); + if (isValidEntry(bundle, headerValue, resource, aliasAttribute)) { + List<URL> resourceUrls = findUrls(bundle, headerValue, true, resource); + if (resourceUrls != null && !resourceUrls.isEmpty()) { + Set<String> paths = bundleToKey.get(bundle); + if (paths == null) { + paths = new HashSet<String>(); + bundleToKey.put(bundle, paths); + } + for (URL url : resourceUrls) { + addResource(paths, bundle, resource, aliasAttribute, url); + } + } else { + logger.warn("No resource urls found for resource path [%s] in bundle[%s] with header[%s].", resource, + bundleName, headerValue); + } + } + } + } + } + + private List<URL> findUrls(Bundle bundle, String headerValue, boolean recurse, String... resources) { + List<URL> resourceUrls = new ArrayList<URL>(); + for (String resource : resources) { + int index = resource.lastIndexOf('/'); + String path = index != -1 ? resource.substring(0, index) : "/"; + String resourceName = index != -1 ? resource.substring(index + 1) : resource; + Enumeration<URL> urls = bundle.findEntries(path, resourceName, recurse); + if (urls != null && urls.hasMoreElements()) { + while (urls.hasMoreElements()) { + URL url = urls.nextElement(); + if (!url.toString().endsWith("/")) { + resourceUrls.add(url); + } + } + } else { + logger.error("Unable to find resource[%s] for bundle [%s]. The component header value is [%s]", resource, + bundle.getSymbolicName(), headerValue); + } + } + return resourceUrls; + } + + private void addResource(Set<String> paths, Bundle bundle, String resourceBase, String alias, URL url) { + int index = resourceBase.lastIndexOf('/'); + String path = index != -1 ? resourceBase.substring(0, index) : "/"; + String resourceName = index != -1 ? resourceBase.substring(index + 1) : resourceBase; + + String toStrip = path; + if (!resourceName.contains("*")) { + toStrip += "/" + resourceName; + } + + String urlPath = url.getPath(); + index = urlPath.indexOf(toStrip); + if (index >= 0) { + urlPath = urlPath.substring(index + toStrip.length()); + } + urlPath = JaxRsUtils.normalize(urlPath); + + String pathToMatch = String.format("%s%s", alias, urlPath); + paths.add(pathToMatch); + + Resource resource = new ResourceImpl(bundle.getSymbolicName(), url); + Resource oldResource = pathToResource.put(pathToMatch, resource); + if (oldResource != null && !oldResource.getUrl().equals(url)) { + logger.error("Resource collision detected for path[%s] between 1:[%s] and 2:[%s]. resource-2 will be used.", + pathToMatch, oldResource, resource); + } + } + + private static final class ResourceImpl implements Resource { + private final String bundleName; + private final URL url; + + public ResourceImpl(String bundleName, URL url) { + super(); + this.bundleName = bundleName; + this.url = url; + } + + @Override + public URL getUrl() { + return url; + } + + @Override + public String toString() { + return "resource [bundleName=" + bundleName + ", url=" + url + "]"; + } + } + +} diff --git a/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/resources/JaxRsContributionsResource.java b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/resources/JaxRsContributionsResource.java index f7ffaac112b..73ae6ffd617 100644 --- a/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/resources/JaxRsContributionsResource.java +++ b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/resources/JaxRsContributionsResource.java @@ -11,11 +11,11 @@ package org.eclipse.osee.jaxrs.server.internal.resources; import java.net.URI; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; +import java.util.Collection; import java.util.Dictionary; -import java.util.List; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; import javax.annotation.security.PermitAll; import javax.ws.rs.GET; import javax.ws.rs.Path; @@ -27,6 +27,8 @@ import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; import org.eclipse.osee.jaxrs.ApplicationInfo; import org.eclipse.osee.jaxrs.JaxRsContributionInfo; +import org.eclipse.osee.jaxrs.server.internal.JaxRsResourceManager; +import org.eclipse.osee.jaxrs.server.internal.JaxRsResourceManager.JaxRsResourceVisitor; import org.eclipse.osee.jaxrs.server.internal.JaxRsVisitable; import org.eclipse.osee.jaxrs.server.internal.JaxRsVisitor; import org.osgi.framework.Bundle; @@ -39,18 +41,41 @@ import org.osgi.framework.Constants; public class JaxRsContributionsResource { private final JaxRsVisitable visitable; + private final JaxRsResourceManager resourceManager; - public JaxRsContributionsResource(JaxRsVisitable visitable) { + public JaxRsContributionsResource(JaxRsVisitable visitable, JaxRsResourceManager resourceManager) { super(); this.visitable = visitable; + this.resourceManager = resourceManager; + } + + private String key(String bundleName, String bundleVersion) { + return String.format("%s:%s", bundleName, bundleVersion); + } + + private JaxRsContributionInfo getOrCreateInfo(Map<String, JaxRsContributionInfo> map, String bundleName, String bundleVersion) { + String key = key(bundleName, bundleVersion); + JaxRsContributionInfo info = map.get(key); + if (info == null) { + info = new JaxRsContributionInfo(); + info.setBundleName(bundleName); + info.setVersion(bundleVersion); + map.put(key, info); + } + return info; + } + + private String getServletPath(UriInfo uriInfo) { + String absolutePath = uriInfo.getAbsolutePath().toASCIIString(); + absolutePath = absolutePath.replaceAll("/jaxrs-admin/contributions", ""); + return absolutePath; } @PermitAll @GET @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) - public List<JaxRsContributionInfo> getContributionDetails(final @Context UriInfo uriInfo) { - final List<JaxRsContributionInfo> toReturn = new ArrayList<JaxRsContributionInfo>(); - + public Collection<JaxRsContributionInfo> getContributionDetails(final @Context UriInfo uriInfo) { + final Map<String, JaxRsContributionInfo> contribs = new HashMap<String, JaxRsContributionInfo>(); visitable.accept(new JaxRsVisitor() { @Override public void onApplication(String applicationContext, String componentName, Bundle bundle, Application application) { @@ -59,17 +84,17 @@ public class JaxRsContributionsResource { String bundleName = headers.get(Constants.BUNDLE_SYMBOLICNAME); String bundleVersion = headers.get(Constants.BUNDLE_VERSION); + JaxRsContributionInfo contrib = getOrCreateInfo(contribs, bundleName, bundleVersion); + ApplicationInfo info = new ApplicationInfo(); - info.setBundleName(bundleName); - info.setVersion(bundleVersion); info.setName(componentName); - String absolutePath = getServletPath(); - + String absolutePath = getServletPath(uriInfo); URI build = UriBuilder.fromPath(absolutePath).path(applicationContext).queryParam("_wadl").build(); String path = build.toASCIIString(); info.setUri(path); - toReturn.add(info); + + contrib.getApplications().add(info); } @Override @@ -79,32 +104,32 @@ public class JaxRsContributionsResource { String bundleName = headers.get(Constants.BUNDLE_SYMBOLICNAME); String bundleVersion = headers.get(Constants.BUNDLE_VERSION); - JaxRsContributionInfo info = new JaxRsContributionInfo(); - info.setBundleName(bundleName); - info.setVersion(bundleVersion); - info.setName(componentName); - toReturn.add(info); - } - - private String getServletPath() { - String absolutePath = uriInfo.getAbsolutePath().toASCIIString(); - absolutePath = absolutePath.replaceAll("/jaxrs-admin/contributions", ""); - return absolutePath; + JaxRsContributionInfo contrib = getOrCreateInfo(contribs, bundleName, bundleVersion); + contrib.getProviders().add(componentName); } }); - Collections.sort(toReturn, new Comparator<JaxRsContributionInfo>() { + + resourceManager.accept(new JaxRsResourceVisitor() { @Override - public int compare(JaxRsContributionInfo o1, JaxRsContributionInfo o2) { - int toReturn = o1.getClass().getSimpleName().compareTo(o2.getClass().getSimpleName()); - if (toReturn == 0) { - toReturn = o1.getName().compareTo(o2.getName()); + public void onResource(Bundle bundle, Collection<String> resources) { + Dictionary<String, String> headers = bundle.getHeaders(); + String bundleName = headers.get(Constants.BUNDLE_SYMBOLICNAME); + String bundleVersion = headers.get(Constants.BUNDLE_VERSION); + + JaxRsContributionInfo contrib = getOrCreateInfo(contribs, bundleName, bundleVersion); + + String absolutePath = getServletPath(uriInfo); + + Set<String> staticResources = contrib.getStaticResources(); + for (String resource : resources) { + String uri = UriBuilder.fromPath(absolutePath).path(resource).build().toASCIIString(); + staticResources.add(uri); } - return toReturn; } - }); - return toReturn; + return contribs.values(); } + } diff --git a/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/resources/JaxRsStaticResourceRequestFilter.java b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/resources/JaxRsStaticResourceRequestFilter.java new file mode 100644 index 00000000000..dfaa2acfb78 --- /dev/null +++ b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/resources/JaxRsStaticResourceRequestFilter.java @@ -0,0 +1,136 @@ +/******************************************************************************* + * Copyright (c) 2014 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.jaxrs.server.internal.resources; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URLConnection; +import java.util.Date; +import java.util.List; +import javax.annotation.Priority; +import javax.servlet.ServletContext; +import javax.ws.rs.Priorities; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Request; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.ResponseBuilder; +import javax.ws.rs.core.StreamingOutput; +import javax.ws.rs.core.UriInfo; +import javax.ws.rs.ext.Provider; +import org.eclipse.osee.framework.jdk.core.util.Lib; +import org.eclipse.osee.jaxrs.server.internal.JaxRsResourceManager; +import org.eclipse.osee.jaxrs.server.internal.JaxRsResourceManager.Resource; + +/** + * @author Roberto E. Escobar + */ +@PreMatching +@Priority(Priorities.USER) +@Provider +public class JaxRsStaticResourceRequestFilter implements ContainerRequestFilter { + + private static final String GET_METHOD = "GET"; + private static final String HEAD_METHOD = "HEAD"; + + private JaxRsResourceManager manager; + + @Context + private ServletContext servletContext; + + public void setJaxRsResourceManager(JaxRsResourceManager manager) { + this.manager = manager; + } + + @Override + public void filter(ContainerRequestContext requestContext) throws IOException { + Request request = requestContext.getRequest(); + String method = request.getMethod(); + if (GET_METHOD.equals(method) || HEAD_METHOD.equals(method)) { + UriInfo uriInfo = requestContext.getUriInfo(); + String path = uriInfo.getAbsolutePath().getPath(); + Resource resource = manager.getResource(path); + if (resource != null) { + MultivaluedMap<String, String> headers = requestContext.getHeaders(); + List<MediaType> acceptableMediaTypes = requestContext.getAcceptableMediaTypes(); + Response response = newResponse(servletContext, headers, acceptableMediaTypes, path, resource); + requestContext.abortWith(response); + } + } + } + + private Response newResponse(ServletContext servletContext, MultivaluedMap<String, String> headers, List<MediaType> acceptableMediaTypes, String toMatch, Resource resource) throws IOException { + final URLConnection connection = resource.getUrl().openConnection(); + + long lastModified = connection.getLastModified(); + int contentLength = connection.getContentLength(); + + String etag = null; + if (lastModified != -1 && contentLength != -1) { + etag = String.format("W/\"%s-%s\"", contentLength, lastModified); + } + + String ifNoneMatch = headers.getFirst(HttpHeaders.IF_NONE_MATCH); + if (ifNoneMatch != null && etag != null && ifNoneMatch.indexOf(etag) != -1) { + return Response.notModified().build(); + } + + ResponseBuilder builder = Response.ok(); + if (contentLength != -1) { + builder.header(HttpHeaders.CONTENT_LENGTH, contentLength); + } + + String contentType = null; + if (servletContext != null) { + contentType = servletContext.getMimeType(toMatch); + } + + if (contentType != null) { + builder.type(contentType); + } else { + if (!acceptableMediaTypes.isEmpty()) { + builder.type(acceptableMediaTypes.get(0)); + } + } + + if (lastModified > 0) { + builder.lastModified(new Date(lastModified)); + } + + if (etag != null) { + builder.tag(etag); + } + + StreamingOutput output = new StreamingOutput() { + + @Override + public void write(OutputStream outputStream) throws IOException, WebApplicationException { + InputStream inputStream = null; + try { + inputStream = connection.getInputStream(); + Lib.inputStreamToOutputStream(inputStream, outputStream); + } finally { + Lib.close(inputStream); + } + } + }; + builder.entity(output); + return builder.build(); + } + +}
\ No newline at end of file |