diff options
author | Roberto E. Escobar | 2014-05-30 18:07:08 +0000 |
---|---|---|
committer | Roberto E. Escobar | 2014-05-31 00:40:10 +0000 |
commit | 55ed5debef6a0dfbb31e96e79d7e85452c8cb3e6 (patch) | |
tree | daaa217b8cbc91e7cac7e6d9d066cf5aaf74c418 /plugins/org.eclipse.osee.jaxrs.server | |
parent | 4f99b6fc8ba615602794f04029e7a81426488272 (diff) | |
download | org.eclipse.osee-55ed5debef6a0dfbb31e96e79d7e85452c8cb3e6.tar.gz org.eclipse.osee-55ed5debef6a0dfbb31e96e79d7e85452c8cb3e6.tar.xz org.eclipse.osee-55ed5debef6a0dfbb31e96e79d7e85452c8cb3e6.zip |
refactor: Rename rest.admin to jaxrs.server
Change-Id: Ie8ff9fa1d9c763aeda068f8e8aae920c5242756a
Diffstat (limited to 'plugins/org.eclipse.osee.jaxrs.server')
21 files changed, 1471 insertions, 0 deletions
diff --git a/plugins/org.eclipse.osee.jaxrs.server/.classpath b/plugins/org.eclipse.osee.jaxrs.server/.classpath new file mode 100644 index 00000000000..ad32c83a788 --- /dev/null +++ b/plugins/org.eclipse.osee.jaxrs.server/.classpath @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="src" path="src"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/plugins/org.eclipse.osee.jaxrs.server/.project b/plugins/org.eclipse.osee.jaxrs.server/.project new file mode 100644 index 00000000000..9a67a65965e --- /dev/null +++ b/plugins/org.eclipse.osee.jaxrs.server/.project @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.eclipse.osee.jaxrs.server</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.ManifestBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.SchemaBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.ds.core.builder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.pde.PluginNature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/plugins/org.eclipse.osee.jaxrs.server/META-INF/MANIFEST.MF b/plugins/org.eclipse.osee.jaxrs.server/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..423be072bd9 --- /dev/null +++ b/plugins/org.eclipse.osee.jaxrs.server/META-INF/MANIFEST.MF @@ -0,0 +1,36 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: OSEE JAX-RS Server (Incubation) +Bundle-SymbolicName: org.eclipse.osee.jaxrs.server +Bundle-Version: 0.17.0.qualifier +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Service-Component: OSGI-INF/*.xml +Import-Package: com.google.common.io, + com.sun.jersey.api.container.filter.servlet;version="1.18.0", + com.sun.jersey.api.core, + com.sun.jersey.api.model;version="1.18.0", + com.sun.jersey.api.wadl.config, + com.sun.jersey.server.wadl, + com.sun.jersey.server.wadl.generators, + com.sun.jersey.server.wadl.generators.resourcedoc, + com.sun.jersey.server.wadl.generators.resourcedoc.model, + com.sun.jersey.server.wadl.generators.resourcedoc.xhtml, + com.sun.jersey.spi.container;version="1.18.0", + com.sun.jersey.spi.container.servlet, + javax.servlet;version="2.5.0", + javax.servlet.http;version="2.5.0", + javax.ws.rs, + javax.ws.rs.core, + javax.ws.rs.ext, + org.eclipse.osee.executor.admin, + org.eclipse.osee.authorization.admin, + org.eclipse.osee.framework.jdk.core.type, + org.eclipse.osee.framework.jdk.core.util, + org.eclipse.osee.logger, + org.eclipse.osee.jaxrs, + org.osgi.framework, + org.osgi.service.http +Bundle-Vendor: Eclipse Open System Engineering Environment +Require-Bundle: org.codehaus.jackson.core, + org.codehaus.jackson.jaxrs, + org.codehaus.jackson.mapper diff --git a/plugins/org.eclipse.osee.jaxrs.server/OSGI-INF/jaxrs.application.manager.xml b/plugins/org.eclipse.osee.jaxrs.server/OSGI-INF/jaxrs.application.manager.xml new file mode 100644 index 00000000000..ceeb783b31d --- /dev/null +++ b/plugins/org.eclipse.osee.jaxrs.server/OSGI-INF/jaxrs.application.manager.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="start" deactivate="stop" enabled="true" immediate="true"> + <implementation class="org.eclipse.osee.jaxrs.server.internal.RestServletManager"/> + + <reference interface="org.osgi.service.http.HttpService" name="HttpService" + cardinality="1..1" + policy="static" + bind="setHttpService" /> + + <reference interface="org.eclipse.osee.logger.Log" name="Log" + cardinality="1..1" + policy="static" + bind="setLogger" /> + + + <reference interface="javax.ws.rs.core.Application" name="Application" + cardinality="1..n" + policy="dynamic" + bind="addApplication" + unbind="removeApplication" /> + <reference bind="setExecutorAdmin" cardinality="1..1" interface="org.eclipse.osee.executor.admin.ExecutorAdmin" name="ExecutorAdmin" policy="static"/> + <reference bind="setAuthorizationAdmin" cardinality="1..1" interface="org.eclipse.osee.authorization.admin.AuthorizationAdmin" name="AuthorizationAdmin" policy="static"/> +</scr:component> diff --git a/plugins/org.eclipse.osee.jaxrs.server/build.properties b/plugins/org.eclipse.osee.jaxrs.server/build.properties new file mode 100644 index 00000000000..6210e849b59 --- /dev/null +++ b/plugins/org.eclipse.osee.jaxrs.server/build.properties @@ -0,0 +1,5 @@ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + OSGI-INF/ +source.. = src/ diff --git a/plugins/org.eclipse.osee.jaxrs.server/pom.xml b/plugins/org.eclipse.osee.jaxrs.server/pom.xml new file mode 100644 index 00000000000..5dc7217d890 --- /dev/null +++ b/plugins/org.eclipse.osee.jaxrs.server/pom.xml @@ -0,0 +1,34 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.eclipse.osee</groupId> + <artifactId>org.eclipse.osee.x.core.parent</artifactId> + <version>0.17.0-SNAPSHOT</version> + <relativePath>../../plugins/org.eclipse.osee.x.core.parent</relativePath> + </parent> + + <artifactId>org.eclipse.osee.jaxrs.server</artifactId> + <packaging>eclipse-plugin</packaging> + <name>OSEE JAX-RS Server - (Incubation)</name> + + <build> + <!-- workaround for https://issues.sonatype.org/browse/TYCHO-168 --> + <resources> + <resource> + <directory>src</directory> + <excludes> + <exclude>**/*.java</exclude> + </excludes> + </resource> + </resources> + <plugins> + <plugin> + <groupId>org.eclipse.tycho</groupId> + <artifactId>tycho-source-plugin</artifactId> + </plugin> + </plugins> + </build> +</project>
\ No newline at end of file diff --git a/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/BundleHttpContext.java b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/BundleHttpContext.java new file mode 100644 index 00000000000..6169f91ef4a --- /dev/null +++ b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/BundleHttpContext.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 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 javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.osgi.framework.Bundle; +import org.osgi.service.http.HttpContext; + +/** + * @author Roberto E. Escobar + */ +public class BundleHttpContext implements HttpContext { + + private final ObjectProvider<Iterable<Bundle>> bundlesProvider; + + public BundleHttpContext(ObjectProvider<Iterable<Bundle>> bundlesProvider) { + this.bundlesProvider = bundlesProvider; + } + + @Override + public URL getResource(String path) { + // find first bundle that has an entry for the path + URL toReturn = null; + Iterable<Bundle> bundles = bundlesProvider.get(); + for (Bundle bundle : bundles) { + toReturn = bundle.getEntry(path); + if (toReturn != null) { + return toReturn; + } + } + return toReturn; + } + + @Override + public String getMimeType(String name) { + return null; + } + + @Override + public boolean handleSecurity(HttpServletRequest request, HttpServletResponse response) { + // Assume the container has already performed authentication + return true; + } + +}
\ No newline at end of file diff --git a/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/BundleWadlGeneratorConfig.java b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/BundleWadlGeneratorConfig.java new file mode 100644 index 00000000000..3911c64af50 --- /dev/null +++ b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/BundleWadlGeneratorConfig.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * Copyright (c) 2013 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.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Collections; +import java.util.List; +import org.eclipse.osee.framework.jdk.core.util.Lib; +import org.eclipse.osee.logger.Log; +import org.osgi.framework.Bundle; +import com.google.common.io.InputSupplier; +import com.sun.jersey.api.wadl.config.WadlGeneratorConfig; +import com.sun.jersey.api.wadl.config.WadlGeneratorDescription; +import com.sun.jersey.server.wadl.generators.WadlGeneratorApplicationDoc; +import com.sun.jersey.server.wadl.generators.WadlGeneratorGrammarsSupport; +import com.sun.jersey.server.wadl.generators.resourcedoc.WadlGeneratorResourceDocSupport; + +/** + * @author Roberto E. Escobar + */ +public class BundleWadlGeneratorConfig extends WadlGeneratorConfig { + + private final Log logger; + private final ObjectProvider<Iterable<Bundle>> provider; + + public BundleWadlGeneratorConfig(Log logger, ObjectProvider<Iterable<Bundle>> provider) { + this.logger = logger; + this.provider = provider; + } + + public boolean hasExtendedWadl() { + boolean result = false; + Iterable<Bundle> bundles = provider.get(); + for (Bundle bundle : bundles) { + result = hasExtendedWadl(bundle); + if (result) { + break; + } + } + return result; + } + + @Override + public List<WadlGeneratorDescription> configure() { + List<WadlGeneratorDescription> toReturn; + + InputStream appDocsStream = null; + InputStream grammarsStream = null; + InputStream resourceDocStream = null; + try { + appDocsStream = getAsInputStream("REST-INF/application-doc.xml", "applicationDocs"); + grammarsStream = getAsInputStream("REST-INF/application-grammars.xml", "grammars"); + resourceDocStream = getAsInputStream("REST-INF/resourcedoc.xml", "resourceDoc"); + + toReturn = generator(WadlGeneratorApplicationDoc.class) // + .prop("applicationDocsStream", appDocsStream) // + .generator(WadlGeneratorGrammarsSupport.class) // + .prop("grammarsStream", grammarsStream) // + .generator(WadlGeneratorResourceDocSupport.class) // + .prop("resourceDocStream", resourceDocStream) // + .descriptions(); + } catch (Exception ex) { + logger.error(ex, "Error generating wadl"); + toReturn = Collections.emptyList(); + } finally { + Lib.close(appDocsStream); + Lib.close(grammarsStream); + Lib.close(resourceDocStream); + } + return toReturn; + } + + private static InputSupplier<InputStream> newSupplier(final URL url) { + return new InputSupplier<InputStream>() { + @Override + public InputStream getInput() throws IOException { + return url.openStream(); + } + }; + } + + private InputStream getAsInputStream(String path, String xmlRoot) throws Exception { + RestResourceConcatenator concat = new RestResourceConcatenator(); + concat.initialize(xmlRoot); + Iterable<Bundle> bundles = provider.get(); + for (Bundle bundle : bundles) { + if (hasExtendedWadl(bundle)) { + URL url = bundle.getResource(path); + concat.addResource(newSupplier(url)); + } + } + return concat.getAsInputStream(); + } + + private boolean hasEntries(Bundle bundle, String... paths) { + // if you don't pass in any paths, this will return true + for (String path : paths) { + if (!hasEntry(bundle, path)) { + return false; + } + } + return true; + } + + private boolean hasExtendedWadl(Bundle bundle) { + return hasEntries(bundle, "REST-INF/application-doc.xml", "REST-INF/application-grammars.xml", + "REST-INF/resourcedoc.xml"); + } + + private boolean hasEntry(Bundle bundle, String path) { + return bundle.getEntry(path) != null; + } +} diff --git a/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/GenericExceptionMapper.java b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/GenericExceptionMapper.java new file mode 100644 index 00000000000..941a298f2f8 --- /dev/null +++ b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/GenericExceptionMapper.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright (c) 2013 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 javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.core.Response.Status.Family; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; +import org.eclipse.osee.jaxrs.ErrorResponse; +import org.eclipse.osee.jaxrs.OseeWebApplicationException; +import org.eclipse.osee.logger.Log; + +/** + * @author Roberto E. Escobar + */ +@Provider +public class GenericExceptionMapper implements ExceptionMapper<Throwable> { + + private static final String SEE_HTTP_STATUS_CODES = "See HTTP Status codes"; + private static final String INTERNAL_SERVER_ERROR_TYPE = "Internal Server Error"; + private static final String APPLICATION_EXCEPTION_TYPE = "Web Application Exception"; + private static final String OSEE_APPLICATION_EXCEPTION_TYPE = "Osee Web Application Exception"; + + private final Log logger; + + public GenericExceptionMapper(Log logger) { + super(); + this.logger = logger; + } + + @Override + public Response toResponse(Throwable throwable) { + boolean isError = false; + String logMessage; + + OseeWebApplicationException exception; + if (throwable instanceof OseeWebApplicationException) { + logMessage = OSEE_APPLICATION_EXCEPTION_TYPE; + exception = ((OseeWebApplicationException) throwable); + } else if (throwable instanceof WebApplicationException) { + logMessage = APPLICATION_EXCEPTION_TYPE; + WebApplicationException webAppException = ((WebApplicationException) throwable); + Response response = webAppException.getResponse(); + int statusCode = response.getStatus(); + String message = webAppException.getMessage(); + + javax.ws.rs.core.Response.StatusType status = Status.fromStatusCode(statusCode); + if (status == null) { + status = newStatusType(statusCode, Family.SERVER_ERROR, SEE_HTTP_STATUS_CODES); + } + exception = new OseeWebApplicationException(throwable, status, message); + } else { + isError = true; + logMessage = INTERNAL_SERVER_ERROR_TYPE; + exception = new OseeWebApplicationException(throwable, Status.INTERNAL_SERVER_ERROR); + } + + ErrorResponse errorResponse = exception.getErrorResponse(); + if (isError) { + logger.error(throwable, "%s - [%s]", logMessage, errorResponse); + } else { + logger.info(throwable, "%s - [%s]", logMessage, errorResponse); + } + return exception.getResponse(); + } + + private javax.ws.rs.core.Response.StatusType newStatusType(final int code, final Family family, final String reason) { + return new javax.ws.rs.core.Response.StatusType() { + + @Override + public int getStatusCode() { + return code; + } + + @Override + public Family getFamily() { + return family; + } + + @Override + public String getReasonPhrase() { + return reason; + } + + }; + } +} diff --git a/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/ObjectProvider.java b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/ObjectProvider.java new file mode 100644 index 00000000000..99aaf392c7f --- /dev/null +++ b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/ObjectProvider.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * 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; + +/** + * @author Roberto E. Escobar + */ +public interface ObjectProvider<T> { + + T get(); + +} diff --git a/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/RestComponentFactory.java b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/RestComponentFactory.java new file mode 100644 index 00000000000..5870d61e691 --- /dev/null +++ b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/RestComponentFactory.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2013 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.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import org.eclipse.osee.jaxrs.server.internal.filters.SecureResourceFilterFactory; +import org.eclipse.osee.jaxrs.server.internal.filters.SecurityContextFilter; +import org.eclipse.osee.jaxrs.server.internal.resources.ApplicationsResource; +import org.eclipse.osee.logger.Log; +import org.osgi.framework.Bundle; +import com.sun.jersey.api.core.DefaultResourceConfig; +import com.sun.jersey.api.core.ResourceConfig; +import com.sun.jersey.spi.container.ResourceFilterFactory; +import com.sun.jersey.spi.container.servlet.ServletContainer; + +/** + * @author Roberto E. Escobar + */ +public class RestComponentFactory { + private final Log logger; + private final SecurityContextFilter securityContextFilter; + + private List<Object> defaultSingletonResources; + + public RestComponentFactory(Log logger, SecurityContextFilter securityContextFilter) { + super(); + this.logger = logger; + this.securityContextFilter = securityContextFilter; + } + + public List<ResourceFilterFactory> getResourceFilterFactories() { + SecureResourceFilterFactory filterFactory = new SecureResourceFilterFactory(logger, securityContextFilter); + return Collections.<ResourceFilterFactory> singletonList(filterFactory); + } + + public List<Object> getResourceSingletons() { + if (defaultSingletonResources == null) { + GenericExceptionMapper exceptionMapper = new GenericExceptionMapper(logger); + defaultSingletonResources = Collections.<Object> singletonList(exceptionMapper); + } + return defaultSingletonResources; + } + + public RestServletContainer createContainer(String context) throws Exception { + DefaultResourceConfig config = new DefaultResourceConfig(); + + for (Object resource : getResourceSingletons()) { + config.getSingletons().add(resource); + } + + Map<String, Bundle> bundleMap = new ConcurrentHashMap<String, Bundle>(); + ObjectProvider<Iterable<Bundle>> provider = newBundleProvider(bundleMap); + config.getProperties().put(ResourceConfig.PROPERTY_RESOURCE_FILTER_FACTORIES, getResourceFilterFactories()); + + BundleHttpContext bundleContext = new BundleHttpContext(provider); + BundleWadlGeneratorConfig wadlGenerator = new BundleWadlGeneratorConfig(logger, provider); + + ApplicationsResource resource = new ApplicationsResource(provider); + config.getSingletons().add(resource); + + ServletContainer container = new ServletContainer(config); + return new RestServletContainer(logger, context, bundleMap, container, config, bundleContext, wadlGenerator); + } + + private ObjectProvider<Iterable<Bundle>> newBundleProvider(final Map<String, Bundle> bundleMap) { + return new ObjectProvider<Iterable<Bundle>>() { + + @Override + public Iterable<Bundle> get() { + return bundleMap.values(); + } + }; + } + +} diff --git a/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/RestResourceConcatenator.java b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/RestResourceConcatenator.java new file mode 100644 index 00000000000..0e96e54e0f4 --- /dev/null +++ b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/RestResourceConcatenator.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2013 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.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.eclipse.osee.framework.jdk.core.type.OseeArgumentException; +import org.eclipse.osee.framework.jdk.core.type.OseeCoreException; +import org.eclipse.osee.framework.jdk.core.util.Conditions; +import org.eclipse.osee.framework.jdk.core.util.Lib; +import com.google.common.io.InputSupplier; + +/** + * @author David W. Miller + */ +public class RestResourceConcatenator { + private final Set<String> resources = new HashSet<String>(); + private String header; + private String footer; + private Pattern resourcePattern = null; + + public void initialize(String xmlTag) { + if (resourcePattern != null) { + throw new OseeArgumentException("Already initialized"); + } + validateTag(xmlTag); + String regex = String.format("(.*?<%s.*?>)(.+?)(</%s>)", xmlTag, xmlTag); + + resourcePattern = Pattern.compile(regex, Pattern.DOTALL); + } + + @Override + public String toString() { + return String.format("%s Object: \n contents {%s}\n", this.getClass().getName(), getResources()); + } + + public void addResource(InputSupplier<? extends InputStream> supplier) throws IOException { + Conditions.checkNotNull(supplier, "InputStreamSupplier"); + InputStream is = null; + try { + is = supplier.getInput(); + processResource(Lib.inputStreamToString(is)); + } finally { + Lib.close(is); + } + } + + public InputStream getAsInputStream() throws UnsupportedEncodingException { + if (resources.isEmpty() || header == null || footer == null) { + throw new OseeCoreException("Rest resource not ready - no data"); + } + return Lib.stringToInputStream(getResources()); + } + + public String getResources() { + StringBuilder sb = new StringBuilder(); + sb.append(header); + for (String resource : resources) { + sb.append(resource); + } + sb.append(footer); + return sb.toString(); + } + + private void processResource(String input) { + Conditions.checkNotNullOrEmpty(input, "bundle resource"); + Matcher match = resourcePattern.matcher(input); + while (match.find()) { + if (resources.isEmpty()) { + header = match.group(1); + footer = match.group(3); + } + resources.add(match.group(2)); + } + } + + private void validateTag(String xmlTag) { + + Conditions.checkNotNullOrEmpty(xmlTag, "xmlTag"); + // resources can only have three tags: "resourceDoc", "applicationDocs" or "grammars" + boolean valid = false; + if (xmlTag.equals("resourceDoc")) { + valid = true; + } else if (xmlTag.equals("applicationDocs")) { + valid = true; + } else if (xmlTag.equals("grammars")) { + valid = true; + } + if (!valid) { + throw new OseeArgumentException("Invalid resource document tag"); + } + } +} diff --git a/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/RestServiceUtils.java b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/RestServiceUtils.java new file mode 100644 index 00000000000..cad00f06899 --- /dev/null +++ b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/RestServiceUtils.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 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.util.Collection; +import java.util.HashMap; +import java.util.Map; +import javax.ws.rs.core.Application; +import org.osgi.framework.ServiceReference; + +/** + * @author Roberto E. Escobar + */ +public final class RestServiceUtils { + + private RestServiceUtils() { + // Utility class + } + + public static String getContextName(ServiceReference<?> reference) { + String contextName = (String) reference.getProperty("context.name"); + if (!isValid(contextName)) { + contextName = getComponentName(reference); + } + return normalize(contextName); + } + + public static String getComponentName(ServiceReference<?> reference) { + return (String) reference.getProperty("component.name"); + } + + public static void checkValid(Application application) throws Exception { + if (application == null) { + throw new IllegalStateException("javax.ws.rs.Application service was null"); + } + if (!hasResources(application)) { + throw new IllegalStateException("javax.ws.rs.Application had no resources declared"); + } + } + + private static boolean hasResources(Application app) { + return !isNullOrEmpty(app.getClasses()) || !isNullOrEmpty(app.getSingletons()); + } + + private static String normalize(String contextName) { + return contextName != null && !contextName.startsWith("/") ? "/" + contextName : contextName; + } + + private static boolean isValid(String value) { + return value != null && value.length() > 0; + } + + private static boolean isNullOrEmpty(Collection<?> collection) { + return collection == null || collection.isEmpty(); + } + + public static Map<String, String> toMap(String componentName, String contextName) { + Map<String, String> data = new HashMap<String, String>(); + data.put("component.name", componentName); + data.put("context.name", contextName); + return data; + } + +} diff --git a/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/RestServletContainer.java b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/RestServletContainer.java new file mode 100644 index 00000000000..43e10443624 --- /dev/null +++ b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/RestServletContainer.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2013 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.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import javax.ws.rs.core.Application; +import org.eclipse.osee.logger.Log; +import org.osgi.framework.Bundle; +import org.osgi.service.http.HttpContext; +import com.sun.jersey.api.core.DefaultResourceConfig; +import com.sun.jersey.api.core.ResourceConfig; +import com.sun.jersey.spi.container.servlet.ServletContainer; + +/** + * @author David W. Miller + */ +public class RestServletContainer { + private final Map<String, Application> applications = new ConcurrentHashMap<String, Application>(); + + private final Log logger; + private final String baseContext; + private final Map<String, Bundle> bundles; + private final ServletContainer container; + private final DefaultResourceConfig resourceConfig; + private final HttpContext context; + private final BundleWadlGeneratorConfig wadl; + + public RestServletContainer(Log logger, String baseContext, Map<String, Bundle> bundles, ServletContainer container, DefaultResourceConfig resourceConfig, HttpContext context, BundleWadlGeneratorConfig wadl) { + super(); + this.logger = logger; + this.baseContext = baseContext; + this.bundles = bundles; + this.container = container; + this.resourceConfig = resourceConfig; + this.context = context; + this.wadl = wadl; + } + + public String getContext() { + return baseContext; + } + + public void addApplication(String key, Bundle bundle, Application application) { + logger.debug("Add - servlet context[%s] - application[%s]", getContext(), key); + applications.put(key, application); + resourceConfig.add(application); + bundles.put(key, bundle); + updateWadlSupport(); + } + + private void updateWadlSupport() { + Map<String, Object> properties = resourceConfig.getProperties(); + if (wadl.hasExtendedWadl()) { + properties.put(ResourceConfig.PROPERTY_WADL_GENERATOR_CONFIG, wadl); + } else { + properties.remove(ResourceConfig.PROPERTY_WADL_GENERATOR_CONFIG); + } + } + + public void removeApplication(String key) { + logger.debug("Remove - servlet context[%s] - application[%s]", getContext(), key); + Application remove = applications.remove(key); + if (remove != null) { + removeResources(resourceConfig.getClasses(), remove.getClasses()); + removeResources(resourceConfig.getSingletons(), remove.getSingletons()); + } + Bundle bundle = bundles.remove(key); + if (bundle != null) { + updateWadlSupport(); + } + } + + public void cleanUp() { + for (String key : applications.keySet()) { + removeApplication(key); + } + } + + private void removeResources(Set<?> set, Set<?> toRemove) { + set.removeAll(toRemove); + } + + public boolean isEmpty() { + return applications.isEmpty(); + } + + public void destroy() { + getContainer().destroy(); + } + + public void reload() { + getContainer().reload(); + } + + public ServletContainer getContainer() { + return container; + } + + public HttpContext getHttpContext() { + return context; + } + +} diff --git a/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/RestServletManager.java b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/RestServletManager.java new file mode 100644 index 00000000000..4a961dce797 --- /dev/null +++ b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/RestServletManager.java @@ -0,0 +1,175 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 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.util.HashSet; +import java.util.Set; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import javax.ws.rs.core.Application; +import org.eclipse.osee.authorization.admin.AuthorizationAdmin; +import org.eclipse.osee.executor.admin.CancellableCallable; +import org.eclipse.osee.executor.admin.ExecutorAdmin; +import org.eclipse.osee.jaxrs.server.internal.filters.SecurityContextFilter; +import org.eclipse.osee.jaxrs.server.internal.filters.SecurityContextProviderImpl; +import org.eclipse.osee.logger.Log; +import org.osgi.framework.ServiceReference; +import org.osgi.service.http.HttpService; + +/** + * @author Roberto E. Escobar + */ +public class RestServletManager { + + private static final ApplicationEntry END_OF_QUEUE = new ApplicationEntry(Op.END_OF_QUEUE, null); + + private final LinkedBlockingQueue<ApplicationEntry> pending = new LinkedBlockingQueue<ApplicationEntry>(); + + private HttpService httpService; + private Log logger; + private ExecutorAdmin executorAdmin; + private AuthorizationAdmin authorizationAdmin; + + private final AtomicReference<RestServletRegistry> registryRef = new AtomicReference<RestServletRegistry>(); + private final AtomicReference<Future<?>> futureRef = new AtomicReference<Future<?>>(); + + public void setHttpService(HttpService httpService) { + this.httpService = httpService; + } + + public void setLogger(Log logger) { + this.logger = logger; + } + + public void setExecutorAdmin(ExecutorAdmin executorAdmin) { + this.executorAdmin = executorAdmin; + } + + public void setAuthorizationAdmin(AuthorizationAdmin authorizationAdmin) { + this.authorizationAdmin = authorizationAdmin; + } + + public void start() throws Exception { + SecurityContextProvider contextProvider = new SecurityContextProviderImpl(logger, authorizationAdmin); + SecurityContextFilter securityFilter = new SecurityContextFilter(contextProvider); + + RestComponentFactory factory = new RestComponentFactory(logger, securityFilter); + RestServletRegistry newRegistry = new RestServletRegistry(logger, httpService, factory); + RestServletRegistry registry = registryRef.getAndSet(newRegistry); + if (registry != null) { + registry.cleanUp(); + } + + CancellableCallable<Void> callable = newRegistrationHelper(); + Future<?> newFuture = executorAdmin.schedule(callable); + Future<?> future = futureRef.getAndSet(newFuture); + stopWorker(future); + } + + public void stop() { + pending.offer(END_OF_QUEUE); + Future<?> future = futureRef.getAndSet(null); + stopWorker(future); + + RestServletRegistry registry = registryRef.getAndSet(null); + if (registry != null) { + registry.cleanUp(); + } + } + + private void stopWorker(Future<?> future) { + if (future != null) { + try { + future.get(3, TimeUnit.SECONDS); + } catch (Exception ex) { + logger.warn(ex, "Error waiting for registration worker to complete"); + future.cancel(true); + } + } + } + + public void addApplication(ServiceReference<Application> reference) { + pending.offer(new ApplicationEntry(Op.ADD, reference)); + } + + public void removeApplication(ServiceReference<Application> reference) { + pending.offer(new ApplicationEntry(Op.REMOVE, reference)); + } + + private CancellableCallable<Void> newRegistrationHelper() { + return new CancellableCallable<Void>() { + @Override + public Void call() throws Exception { + logger.debug("Start - REST Application Registration Helper"); + boolean isEndOfQueue = false; + while (!isEndOfQueue) { + Set<ApplicationEntry> toProcess = new HashSet<ApplicationEntry>(); + ApplicationEntry entry = pending.take(); + pending.drainTo(toProcess); + toProcess.add(entry); + + for (ApplicationEntry item : toProcess) { + checkForCancelled(); + + RestServletRegistry registry = registryRef.get(); + if (registry != null) { + ServiceReference<Application> reference = item.getReference(); + switch (item.getOp()) { + case ADD: + registry.register(reference); + break; + case REMOVE: + registry.deregister(reference); + break; + default: + isEndOfQueue = true; + break; + } + } else { + logger.debug("Registry was null while worker was processing [reg/de-reg]-istrations"); + isEndOfQueue = true; + } + } + } + logger.debug("Stop - REST Application Registration Helper"); + return null; + } + }; + } + + private static enum Op { + ADD, + REMOVE, + END_OF_QUEUE; + } + + private static final class ApplicationEntry { + private final Op op; + private final ServiceReference<Application> reference; + + public ApplicationEntry(Op op, ServiceReference<Application> reference) { + super(); + this.op = op; + this.reference = reference; + } + + public Op getOp() { + return op; + } + + public ServiceReference<Application> getReference() { + return reference; + } + + } +} diff --git a/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/RestServletRegistry.java b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/RestServletRegistry.java new file mode 100644 index 00000000000..d4e24da8eb7 --- /dev/null +++ b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/RestServletRegistry.java @@ -0,0 +1,138 @@ +/******************************************************************************* + * Copyright (c) 2013 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.util.Iterator; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.FutureTask; +import javax.ws.rs.core.Application; +import org.eclipse.osee.framework.jdk.core.type.LazyObject; +import org.eclipse.osee.logger.Log; +import org.osgi.framework.Bundle; +import org.osgi.framework.ServiceReference; +import org.osgi.service.http.HttpContext; +import org.osgi.service.http.HttpService; +import com.sun.jersey.spi.container.servlet.ServletContainer; + +/** + * @author Roberto E. Escobar + */ +public class RestServletRegistry { + + private final ConcurrentHashMap<String, LazyObject<RestServletContainer>> servlets = + new ConcurrentHashMap<String, LazyObject<RestServletContainer>>(); + + private final Log logger; + private final HttpService httpService; + private final RestComponentFactory factory; + + public RestServletRegistry(Log logger, HttpService httpService, RestComponentFactory factory) { + super(); + this.logger = logger; + this.httpService = httpService; + this.factory = factory; + } + + public void register(ServiceReference<Application> reference) throws Exception { + String componentName = RestServiceUtils.getComponentName(reference); + String contextName = RestServiceUtils.getContextName(reference); + + LazyObject<RestServletContainer> provider = getProvider(contextName); + RestServletContainer container = provider.get(); + + Bundle bundle = reference.getBundle(); + Application application = bundle.getBundleContext().getService(reference); + container.addApplication(componentName, bundle, application); + + container.reload(); + } + + public void deregister(ServiceReference<Application> reference) { + String componentName = RestServiceUtils.getComponentName(reference); + String contextName = RestServiceUtils.getContextName(reference); + + LazyObject<RestServletContainer> provider = getProvider(contextName); + RestServletContainer container = provider.get(); + + container.removeApplication(componentName); + if (container.isEmpty()) { + removeContainer(provider); + } else { + container.reload(); + } + } + + public void cleanUp() { + Iterator<LazyObject<RestServletContainer>> iterator = servlets.values().iterator(); + while (iterator.hasNext()) { + LazyObject<RestServletContainer> provider = iterator.next(); + RestServletContainer container = provider.get(); + container.cleanUp(); + removeContainer(provider); + iterator.remove(); + } + servlets.clear(); + } + + private void removeContainer(LazyObject<RestServletContainer> provider) { + RestServletContainer container = provider.get(); + String contextName = container.getContext(); + + logger.debug("Remove - servlet context[%s]", contextName); + servlets.remove(contextName); + httpService.unregister(contextName); + container.destroy(); + provider.invalidate(); + } + + private LazyObject<RestServletContainer> getProvider(final String contextName) { + LazyObject<RestServletContainer> provider = servlets.get(contextName); + if (provider == null) { + LazyObject<RestServletContainer> newProvider = new ServletContainerProvider(contextName); + provider = servlets.putIfAbsent(contextName, newProvider); + if (provider == null) { + provider = newProvider; + } + } + return provider; + } + + private class ServletContainerProvider extends LazyObject<RestServletContainer> implements ObjectProvider<RestServletContainer> { + + private final String contextName; + + public ServletContainerProvider(String contextName) { + super(); + this.contextName = contextName; + } + + @Override + protected FutureTask<RestServletContainer> createLoaderTask() { + Callable<RestServletContainer> newCallable = new Callable<RestServletContainer>() { + @Override + public RestServletContainer call() throws Exception { + logger.debug("Add - servlet context[%s]", contextName); + RestServletContainer container = factory.createContainer(contextName); + + String name = container.getContext(); + ServletContainer servletContainer = container.getContainer(); + HttpContext httpContext = container.getHttpContext(); + + httpService.registerServlet(name, servletContainer, null, httpContext); + return container; + } + }; + return new FutureTask<RestServletContainer>(newCallable); + } + } + +} diff --git a/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/SecurityContextProvider.java b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/SecurityContextProvider.java new file mode 100644 index 00000000000..927e9c04a5f --- /dev/null +++ b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/SecurityContextProvider.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2013 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 javax.ws.rs.core.SecurityContext; +import com.sun.jersey.api.core.HttpRequestContext; + +/** + * @author Roberto E. Escobar + */ +public interface SecurityContextProvider { + + SecurityContext getSecurityContext(HttpRequestContext requestContext); + +} diff --git a/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/filters/SecureResourceFilterFactory.java b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/filters/SecureResourceFilterFactory.java new file mode 100644 index 00000000000..3aafaa82778 --- /dev/null +++ b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/filters/SecureResourceFilterFactory.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2013 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.filters; + +import java.util.ArrayList; +import java.util.List; +import org.eclipse.osee.jaxrs.NoSecurityFilter; +import org.eclipse.osee.logger.Log; +import com.sun.jersey.api.container.filter.servlet.RolesAllowedResourceFilterFactory; +import com.sun.jersey.api.model.AbstractMethod; +import com.sun.jersey.spi.container.ResourceFilter; + +/** + * Ensures the security context filter {@link SecurityContextFilter} is always the first filter in the chain. + * + * @author Roberto E. Escobar + */ +public class SecureResourceFilterFactory extends RolesAllowedResourceFilterFactory { + + private static final String SECURE = "SECURE"; + private static final String INSECURE = "SKIPPED"; + + private final Log logger; + private final SecurityContextFilter securityContextFilter; + + public SecureResourceFilterFactory(Log logger, SecurityContextFilter securityContextFilter) { + super(); + this.logger = logger; + this.securityContextFilter = securityContextFilter; + } + + @Override + public List<ResourceFilter> create(AbstractMethod am) { + List<ResourceFilter> securityFilters = super.create(am); + if (securityFilters == null) { + securityFilters = new ArrayList<ResourceFilter>(); + } else { + securityFilters = new ArrayList<ResourceFilter>(securityFilters); + } + + boolean secure = isSecured(am); + if (secure) { + securityFilters.add(0, securityContextFilter); + } + logger.info("REST Security Filter: [%s] [%s]", secure ? SECURE : INSECURE, am); + return securityFilters; + } + + private boolean isSecured(AbstractMethod am) { + return !am.isAnnotationPresent(NoSecurityFilter.class) && // + !am.getResource().isAnnotationPresent(NoSecurityFilter.class); + } +}
\ No newline at end of file diff --git a/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/filters/SecurityContextFilter.java b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/filters/SecurityContextFilter.java new file mode 100644 index 00000000000..a50be71487f --- /dev/null +++ b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/filters/SecurityContextFilter.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2013 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.filters; + +import javax.ws.rs.core.SecurityContext; +import javax.ws.rs.ext.Provider; +import org.eclipse.osee.jaxrs.server.internal.SecurityContextProvider; +import com.sun.jersey.spi.container.ContainerRequest; +import com.sun.jersey.spi.container.ContainerRequestFilter; +import com.sun.jersey.spi.container.ContainerResponseFilter; +import com.sun.jersey.spi.container.ResourceFilter; + +/** + * @author Roberto E. Escobar + */ +@Provider +public class SecurityContextFilter implements ResourceFilter, ContainerRequestFilter { + + private final SecurityContextProvider contextProvider; + + public SecurityContextFilter(SecurityContextProvider contextProvider) { + super(); + this.contextProvider = contextProvider; + } + + @Override + public ContainerRequest filter(ContainerRequest request) { + SecurityContext securityContext = contextProvider.getSecurityContext(request); + if (securityContext != null) { + request.setSecurityContext(securityContext); + } + return request; + } + + @Override + public ContainerRequestFilter getRequestFilter() { + return this; + } + + @Override + public ContainerResponseFilter getResponseFilter() { + return null; + } + +} diff --git a/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/filters/SecurityContextProviderImpl.java b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/filters/SecurityContextProviderImpl.java new file mode 100644 index 00000000000..7d2d677527b --- /dev/null +++ b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/filters/SecurityContextProviderImpl.java @@ -0,0 +1,138 @@ +/******************************************************************************* + * Copyright (c) 2013 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.filters; + +import java.security.Principal; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.core.SecurityContext; +import org.eclipse.osee.authorization.admin.Authorization; +import org.eclipse.osee.authorization.admin.AuthorizationAdmin; +import org.eclipse.osee.authorization.admin.AuthorizationRequest; +import org.eclipse.osee.authorization.admin.AuthorizationRequestBuilder; +import org.eclipse.osee.framework.jdk.core.util.Strings; +import org.eclipse.osee.jaxrs.OseeWebApplicationException; +import org.eclipse.osee.jaxrs.server.internal.SecurityContextProvider; +import org.eclipse.osee.logger.Log; +import com.sun.jersey.api.core.HttpRequestContext; + +/** + * @author Roberto E. Escobar + */ +public class SecurityContextProviderImpl implements SecurityContextProvider { + + protected static final String HTTP_DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz"; + protected static final String AUTHORIZATION_HEADER = "Authorization"; + protected static final String DATE_HEADER = "Date"; + + private final Log logger; + private final AuthorizationAdmin authorizationAdmin; + + public SecurityContextProviderImpl(Log logger, AuthorizationAdmin authorizationAdmin) { + super(); + this.logger = logger; + this.authorizationAdmin = authorizationAdmin; + } + + @Override + public SecurityContext getSecurityContext(HttpRequestContext request) { + boolean isSecure = request.isSecure(); + Date requestDate = asDate(request.getHeaderValue(DATE_HEADER)); + String authType = request.getHeaderValue(AUTHORIZATION_HEADER); + String path = request.getPath(); + String method = request.getMethod(); + + AuthorizationRequest authRequest = AuthorizationRequestBuilder.newBuilder()// + .secure(isSecure)// + .date(requestDate) // + .authorizationType(authType) // + .method(method) // + .path(path) // + .build(); + + Authorization authorized = authorizationAdmin.authorize(authRequest); + return new SecurityContextImpl(authorized); + } + + private Date asDate(String value) { + Date toReturn = null; + if (Strings.isValid(value)) { + SimpleDateFormat format = new SimpleDateFormat(HTTP_DATE_FORMAT); + try { + toReturn = format.parse(value); + } catch (ParseException ex) { + logger.warn(ex, "Error parsing http request date [%s]", value); + } + } + + if (toReturn == null) { + toReturn = new Date(); + } + return toReturn; + } + + private static final class SecurityContextImpl implements SecurityContext { + + private final Authorization authorization; + + public SecurityContextImpl(Authorization authorized) { + super(); + this.authorization = authorized; + } + + @Override + public Principal getUserPrincipal() { + if (authorization == null) { + throw new InvalidAuthorizationHeaderException(); + } + return authorization.getPrincipal(); + } + + @Override + public boolean isUserInRole(String role) { + if (authorization == null) { + throw new InvalidAuthorizationHeaderException(); + } + return authorization.isInRole(role); + } + + @Override + public boolean isSecure() { + if (authorization == null) { + throw new InvalidAuthorizationHeaderException(); + } + return authorization.isSecure(); + } + + @Override + public String getAuthenticationScheme() { + if (authorization == null) { + throw new InvalidAuthorizationHeaderException(); + } + return authorization.getScheme(); + } + } + + private static final class InvalidAuthorizationHeaderException extends OseeWebApplicationException { + + private static final long serialVersionUID = -7930846912940821509L; + + public static final String ERROR_MESSAGE = + "Authorization Error - This could be due to missing properties in the header."; + + public InvalidAuthorizationHeaderException() { + super(Status.UNAUTHORIZED, ERROR_MESSAGE); + } + + } +} diff --git a/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/resources/ApplicationsResource.java b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/resources/ApplicationsResource.java new file mode 100644 index 00000000000..5cd18ceef84 --- /dev/null +++ b/plugins/org.eclipse.osee.jaxrs.server/src/org/eclipse/osee/jaxrs/server/internal/resources/ApplicationsResource.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * 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.util.ArrayList; +import java.util.Arrays; +import java.util.Dictionary; +import java.util.List; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.MediaType; +import org.eclipse.osee.jaxrs.ApplicationInfo; +import org.eclipse.osee.jaxrs.server.internal.ObjectProvider; +import org.eclipse.osee.jaxrs.server.internal.RestServiceUtils; +import org.osgi.framework.Bundle; +import org.osgi.framework.Constants; +import org.osgi.framework.ServiceReference; + +/** + * @author Roberto E. Escobar + */ +@Path("application-details") +public class ApplicationsResource { + + private final ObjectProvider<Iterable<Bundle>> provider; + + public ApplicationsResource(ObjectProvider<Iterable<Bundle>> provider) { + super(); + this.provider = provider; + } + + @GET + @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public List<ApplicationInfo> getApplicationsInfo() { + List<ApplicationInfo> toReturn = new ArrayList<ApplicationInfo>(); + Iterable<Bundle> bundles = provider.get(); + for (Bundle bundle : bundles) { + Dictionary<String, String> headers = bundle.getHeaders(); + + String bundleName = headers.get(Constants.BUNDLE_SYMBOLICNAME); + String bundleVersion = headers.get(Constants.BUNDLE_VERSION); + + ServiceReference<?>[] references = bundle.getRegisteredServices(); + for (ServiceReference<?> reference : references) { + String[] object = (String[]) reference.getProperty("objectClass"); + String clazzType = Arrays.deepToString(object); + if (clazzType.contains(Application.class.getSimpleName())) { + String componentName = RestServiceUtils.getComponentName(reference); + String contextName = RestServiceUtils.getContextName(reference); + + ApplicationInfo info = new ApplicationInfo(); + info.setBundleName(bundleName); + info.setVersion(bundleVersion); + info.setApplicationName(componentName); + info.setUri(contextName); + toReturn.add(info); + } + + } + } + return toReturn; + } +} |