You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by fm...@apache.org on 2007/09/21 14:11:43 UTC
svn commit: r578081 - in
/incubator/sling/trunk/core/src/main/java/org/apache/sling/core/impl/adapter:
./ ComponentAdapterManager.java ServletComponentAdapter.java
Author: fmeschbe
Date: Fri Sep 21 05:11:43 2007
New Revision: 578081
URL: http://svn.apache.org/viewvc?rev=578081&view=rev
Log:
SLING-6 Run JSPs located in bundles
Added:
incubator/sling/trunk/core/src/main/java/org/apache/sling/core/impl/adapter/
incubator/sling/trunk/core/src/main/java/org/apache/sling/core/impl/adapter/ComponentAdapterManager.java
incubator/sling/trunk/core/src/main/java/org/apache/sling/core/impl/adapter/ServletComponentAdapter.java
Added: incubator/sling/trunk/core/src/main/java/org/apache/sling/core/impl/adapter/ComponentAdapterManager.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/core/src/main/java/org/apache/sling/core/impl/adapter/ComponentAdapterManager.java?rev=578081&view=auto
==============================================================================
--- incubator/sling/trunk/core/src/main/java/org/apache/sling/core/impl/adapter/ComponentAdapterManager.java (added)
+++ incubator/sling/trunk/core/src/main/java/org/apache/sling/core/impl/adapter/ComponentAdapterManager.java Fri Sep 21 05:11:43 2007
@@ -0,0 +1,219 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.core.impl.adapter;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.Servlet;
+
+import org.apache.sling.component.Component;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.component.ComponentConstants;
+import org.osgi.service.component.ComponentContext;
+
+/**
+ * The <code>ComponentAdapterManager</code> is a component watching for
+ * <code>javax.servlet.Servlet</code> services being registered. Each registered
+ * servlet is then wrapped in a Component adapter and registered (again) as a
+ * <code>Component</code> which is then recognized by Sling for rendering.
+ *
+ * @scr.component metatype="false"
+ * @scr.property name="service.vendor" value="The Apache Software Foundation"
+ * @scr.property name="service.description" value="Component Adapter Manager"
+ * @scr.reference name="Servlet" interface="javax.servlet.Servlet"
+ * cardinality="0..n" policy="dynamic"
+ */
+public class ComponentAdapterManager {
+
+ /**
+ * The prefix prependend to private property names added to the adapted
+ * Component (value is "sling.component.adapter.")
+ */
+ public static final String ADAPTED_PROPERTY_PREFIX = "sling.component.adapter.";
+
+ /**
+ * The prefix prependend to service description to be used for the adapter
+ * (value is "Component Adapter to ")
+ */
+ public static final String ADAPTED_DESCRIPTION_PREFIX = "Component Adapter to ";
+
+ /**
+ * The set of service properties considered private. These properties are
+ * still copied from the adapted service to the adapter service but their
+ * keys are prefixed with the {@link #ADAPTED_PROPERTY_PREFIX}.
+ */
+ private static final Set<String> privateProperties;
+
+ /*
+ * Static initializer to set up the set of private property names
+ */
+ static {
+ privateProperties = new HashSet<String>();
+
+ // well-known service properties
+ privateProperties.add(Constants.OBJECTCLASS);
+ privateProperties.add(Constants.SERVICE_ID);
+ privateProperties.add(Constants.SERVICE_PID);
+ privateProperties.add(Constants.SERVICE_RANKING);
+
+ // configuration admin standard properties
+ privateProperties.add(ConfigurationAdmin.SERVICE_BUNDLELOCATION);
+ privateProperties.add(ConfigurationAdmin.SERVICE_FACTORYPID);
+
+ // declarative services standard properties
+ privateProperties.add(ComponentConstants.COMPONENT_ID);
+ privateProperties.add(ComponentConstants.COMPONENT_NAME);
+ privateProperties.add(ComponentConstants.COMPONENT_FACTORY);
+ }
+
+ private ComponentContext componentContext;
+
+ /**
+ * List of service references bound to this instance while the instance has
+ * not yet been activated. As soon as this instance is activated all
+ * references are resolved into the respective service and adapters are
+ * created and registered.
+ */
+ private final List<ServiceReference> references = new ArrayList<ServiceReference>();
+
+ /**
+ * The map of adapters registered for the adapted adapters.
+ */
+ private final Map<Long, ServiceRegistration> adapters = new HashMap<Long, ServiceRegistration>();
+
+ protected void activate(ComponentContext context) {
+
+ ServiceReference[] refs;
+ synchronized (this) {
+ componentContext = context;
+ refs = references.toArray(new ServiceReference[references.size()]);
+ references.clear();
+ }
+
+ // register the services outside the synchronization to prevent deadlock
+ for (int i = 0; i < refs.length; i++) {
+ doBindServlet(componentContext, refs[i]);
+ }
+ }
+
+ protected void deactivate(ComponentContext context) {
+ ServiceRegistration[] adapterRegs;
+ synchronized (this) {
+ componentContext = null;
+
+ // just to be sure we clear our references
+ references.clear();
+
+ // unregister all adapters now
+ adapterRegs = adapters.values().toArray(
+ new ServiceRegistration[adapters.size()]);
+ adapters.clear();
+ }
+
+ for (int i = 0; i < adapterRegs.length; i++) {
+ try {
+ adapterRegs[i].unregister();
+ } catch (Throwable t) {
+ // ignore
+ }
+ }
+ }
+
+ protected void bindServlet(ServiceReference servletReference) {
+
+ ComponentContext context;
+ synchronized (this) {
+ context = componentContext;
+
+ // if there is no bundle context (yet), store the servlet
+ // reference in the references list
+ if (context == null) {
+ references.add(servletReference);
+ return;
+ }
+ }
+
+ // register the service outside the synchronization to prevent deadlock
+ doBindServlet(context, servletReference);
+ }
+
+ protected synchronized void unbindServlet(ServiceReference servletReference) {
+ Long id = (Long) servletReference.getProperty(Constants.SERVICE_ID);
+
+ ServiceRegistration sr;
+ synchronized (this) {
+ sr = adapters.remove(id);
+ }
+
+ // unregister the service outside the synchronization to prevent
+ // deadlock
+ if (sr != null) {
+ sr.unregister();
+ }
+
+ // just in case ...
+ references.remove(servletReference);
+ }
+
+ private void doBindServlet(ComponentContext context,
+ ServiceReference servletReference) {
+ Servlet servlet = (Servlet) context.locateService("Servlet",
+ servletReference);
+ if (servlet != null) {
+ Dictionary<String, Object> properties = getProperties(servletReference);
+ ServletComponentAdapter adapter = new ServletComponentAdapter(
+ servlet, properties);
+ ServiceRegistration sr = context.getBundleContext().registerService(
+ Component.class.getName(), adapter, properties);
+
+ Long id = (Long) servletReference.getProperty(Constants.SERVICE_ID);
+ synchronized (this) {
+ adapters.put(id, sr);
+ }
+ }
+ }
+
+ private Dictionary<String, Object> getProperties(
+ ServiceReference servletReference) {
+ Hashtable<String, Object> properties = new Hashtable<String, Object>();
+ String[] keys = servletReference.getPropertyKeys();
+ for (String key : keys) {
+ Object value = servletReference.getProperty(key);
+
+ if (privateProperties.contains(key)) {
+ key = ADAPTED_PROPERTY_PREFIX + key;
+ } else if (Constants.SERVICE_DESCRIPTION.equals(key)) {
+ value = ADAPTED_DESCRIPTION_PREFIX + value;
+ }
+
+ properties.put(key, value);
+ }
+ return properties;
+ }
+}
Added: incubator/sling/trunk/core/src/main/java/org/apache/sling/core/impl/adapter/ServletComponentAdapter.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/core/src/main/java/org/apache/sling/core/impl/adapter/ServletComponentAdapter.java?rev=578081&view=auto
==============================================================================
--- incubator/sling/trunk/core/src/main/java/org/apache/sling/core/impl/adapter/ServletComponentAdapter.java (added)
+++ incubator/sling/trunk/core/src/main/java/org/apache/sling/core/impl/adapter/ServletComponentAdapter.java Fri Sep 21 05:11:43 2007
@@ -0,0 +1,232 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.core.impl.adapter;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Enumeration;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+
+import org.apache.sling.component.ComponentException;
+import org.apache.sling.component.ComponentRequest;
+import org.apache.sling.component.ComponentResponse;
+import org.apache.sling.core.components.BaseComponent;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.ComponentConstants;
+
+/**
+ * The <code>ServletComponentAdapter</code> class is a component which adapts
+ * the <code>javax.servlet.Servlet</code> API to the component API. Instances
+ * of this class are managed by the {@link ComponentAdapterManager} to adapt
+ * services registered as <code>javax.servlet.Service</code> to components and
+ * register them as components for use by the system.
+ * <p>
+ * The component ID of instances of this component is deduced from the service
+ * registration properties of the <code>Servlet</code> service which is
+ * adapted. If the service has a <code>component.name</code> property, its
+ * value is used as the component ID. Otherwise, if the service has a
+ * <code>service.pid</code> property, that value is used as the component ID.
+ * If this property is not defined either, the fully qualified name of the
+ * service class is used as the component ID.
+ * <p>
+ * This class only supports the rendering part of a component has no knowledge
+ * of the type of <code>Content</code> referring to it. Therefore the
+ * <code>getContentClassName()</code> always returns <code>null</code> and
+ * instances of the content class can obviously not be created.
+ * <p>
+ * <b>Servlet Init Parameters</b>
+ * <p>
+ * The service properties of the originally registered <code>Servlet</code>
+ * service are reused as service properties for the registered component with
+ * some notable exceptions:
+ * <dl>
+ * <dt>objectClass, service.id, service.pid, service.ranking,
+ * service.bundleLocation, service.factoryPid, component.id, component.name,
+ * component.factory</dt>
+ * <dd>These properties are copied and their name is prefixed with the
+ * {@link ComponentAdapterManager#ADAPTED_PROPERTY_PREFIX}</dd>
+ * <dt>service.description</dt>
+ * <dd>This property is copied but the value is prefixed with the
+ * {@link ComponentAdapterManager#ADAPTED_DESCRIPTION_PREFIX}</dd>
+ * </dl>
+ */
+class ServletComponentAdapter extends BaseComponent {
+
+ private static final String ADAPTED_COMPONENT_NAME = ComponentAdapterManager.ADAPTED_PROPERTY_PREFIX
+ + ComponentConstants.COMPONENT_NAME;
+
+ private static final String ADAPTED_SERVICE_PID = ComponentAdapterManager.ADAPTED_PROPERTY_PREFIX
+ + Constants.SERVICE_PID;
+
+ /**
+ * The servlet service to which this instance adapts.
+ */
+ private final Servlet delegatee;
+
+ /**
+ * The service properties used to register this Component as an OSGi service
+ * and as init-parameters to the adapted servlet.
+ */
+ private final Dictionary<String, ?> properties;
+
+ /**
+ * Creates an instance of this adapter.
+ *
+ * @param delegatee The adapted Servlet
+ * @param properties The service properties of this Component service also
+ * used as init-parameters for the servlet and to extract the
+ * component ID.
+ */
+ ServletComponentAdapter(Servlet delegatee, Dictionary<String, ?> properties) {
+ this.delegatee = delegatee;
+ this.properties = properties;
+
+ // get the component id
+ String id = (String) properties.get(ADAPTED_COMPONENT_NAME);
+ if (id == null) {
+ id = (String) properties.get(ADAPTED_SERVICE_PID);
+ if (id == null) {
+ id = delegatee.getClass().getName();
+ }
+ }
+ setComponentId(id);
+ }
+
+ /**
+ * Calls the <code>Servlet.init(ServletConfig)</code> method with a
+ * servlet configuration as follows:
+ * <ul>
+ * <li>The service parameter of this Component service are used init-params
+ * <li>The ID of this component is used as the servlet name
+ * <li>The Component context of this component is used as the servlet
+ * context. </li>
+ *
+ * @throws ComponentException Wrapping the <code>ServletException</code>
+ * thrown by the <code>Servlet.init</code> method.
+ */
+ @Override
+ protected void doInit() throws ComponentException {
+ try {
+ delegatee.init(new ServletConfig() {
+
+ // ensure service properties are converted to string
+ public String getInitParameter(String name) {
+ Object prop = properties.get(name);
+ if (prop == null) {
+ return null;
+ }
+
+ return prop.toString();
+ }
+
+ // inherit init-params from service properties
+ public Enumeration<String> getInitParameterNames() {
+ return properties.keys();
+ }
+
+ // the component's context is used as the ServletContext
+ public ServletContext getServletContext() {
+ return getComponentContext();
+ }
+
+ // the servlet name is equivalent to the component ID
+ public String getServletName() {
+ return getId();
+ }
+ });
+ } catch (ServletException se) {
+ throw toComponentException(se);
+ }
+ }
+
+ /**
+ * Calls the <code>Servlet.service(ServletRequest, ServletResponse)</code>
+ * method using the <code>request</code> and <code>response</code>
+ * objects unmodified.
+ *
+ * @param request The <code>ComponentRequest</code> used as the request
+ * parameter to the <code>Servlet.service</code> method.
+ * @param response The <code>ComponentResponse</code> used as the response
+ * parameter to the <code>Servlet.service</code> method.
+ * @throws ComponentException Wrapping the <code>ServletException</code>
+ * thrown by the <code>Servlet.service</code> method.
+ * @throws IOException If thrown by the <code>Servlet.service</code>
+ * method.
+ */
+ public void service(ComponentRequest request, ComponentResponse response)
+ throws ComponentException, IOException {
+ try {
+ delegatee.service(request, response);
+ } catch (ServletException se) {
+ throw toComponentException(se);
+ }
+ }
+
+ /**
+ * Calls the <code>Servlet.destroy()</code> method to take the servlet out
+ * of service.
+ */
+ @Override
+ public void destroy() {
+ delegatee.destroy();
+ super.destroy();
+ }
+
+ /**
+ * Converts the given <code>ServletException</code> into a
+ * <code>ComponentException</code> as follows:
+ * <ul>
+ * <li>If the servlet exception is a <code>ComponentException</code> the
+ * exception is just returned.
+ * <li>Else, if the root cause of the servlet exception is a
+ * <code>ComponentException</code> the root cause is returned.
+ * <li>Else, if the root cause is not <code>null</code>, the root cause
+ * is wrapped in a <code>ComponentException</code> using the message of
+ * the root cause as the new exception's message.
+ * <li>Else, the servlet exception is wrapped in a
+ * <code>ComponentException</code> using the message of the servlet
+ * exception as the new exception's message.
+ * </ul>
+ *
+ * @param se The <code>ServletException</code> to turn into a
+ * <code>ComponentException</code>
+ * @return The <code>ComponentException</code> created from the servlet
+ * exception.
+ */
+ private ComponentException toComponentException(ServletException se) {
+ if (se instanceof ComponentException) {
+ return (ComponentException) se;
+ }
+
+ Throwable cause = se.getRootCause();
+ if (cause instanceof ComponentException) {
+ return (ComponentException) cause;
+ }
+
+ if (cause == null) {
+ cause = se;
+ }
+
+ return new ComponentException(cause.getMessage(), cause);
+ }
+}