You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by cl...@apache.org on 2013/02/28 11:27:24 UTC
svn commit: r1451167 [7/7] - in /felix/trunk/ipojo/handler/temporal: ./ doc/
src/ temporal-dependency-handler-it/ temporal-dependency-handler-it/src/
temporal-dependency-handler-it/src/it/
temporal-dependency-handler-it/src/it/temporal-it/ temporal-dep...
Added: felix/trunk/ipojo/handler/temporal/temporal-dependency-handler/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/handler/temporal/temporal-dependency-handler/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalHandler.java?rev=1451167&view=auto
==============================================================================
--- felix/trunk/ipojo/handler/temporal/temporal-dependency-handler/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalHandler.java (added)
+++ felix/trunk/ipojo/handler/temporal/temporal-dependency-handler/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalHandler.java Thu Feb 28 10:27:21 2013
@@ -0,0 +1,315 @@
+/*
+ * 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.felix.ipojo.handler.temporal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.FieldMetadata;
+import org.apache.felix.ipojo.parser.MethodMetadata;
+import org.apache.felix.ipojo.parser.PojoMetadata;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.apache.felix.ipojo.util.DependencyStateListener;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+
+/**
+* Temporal dependency handler.
+* A temporal dependency waits (block) for the availability of the service.
+* If no provider arrives in the specified among of time, a runtime exception is thrown.
+* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+*/
+public class TemporalHandler extends PrimitiveHandler implements DependencyStateListener {
+
+ /**
+ * Default timeout if not specified.
+ */
+ public static final int DEFAULT_TIMEOUT = 3000;
+
+ /**
+ * No policy.
+ */
+ public static final int NO_POLICY = 0;
+ /**
+ * Uses a nullable object.
+ */
+ public static final int NULLABLE = 1;
+ /**
+ * Uses a default-implementation object.
+ */
+ public static final int DEFAULT_IMPLEMENTATION = 2;
+ /**
+ * Uses an empty array.
+ */
+ public static final int EMPTY = 3;
+ /**
+ * Uses {@code null}.
+ */
+ public static final int NULL = 4;
+
+ /**
+ * The handler namespace.
+ */
+ public static final String NAMESPACE = "org.apache.felix.ipojo.handler.temporal";
+
+ /**
+ * The list of managed dependencies.
+ */
+ private List/*<deps>*/ m_dependencies = new ArrayList(1);
+
+ /**
+ * Start method. Starts managed dependencies.
+ * @see org.apache.felix.ipojo.Handler#start()
+ */
+ public void start() {
+ for (int i = 0; i < m_dependencies.size(); i++) {
+ ((TemporalDependency) m_dependencies.get(i)).start();
+ }
+ }
+
+ /**
+ * Stop method. Stops managed dependencies.
+ * @see org.apache.felix.ipojo.Handler#stop()
+ */
+ public void stop() {
+ for (int i = 0; i < m_dependencies.size(); i++) {
+ ((TemporalDependency) m_dependencies.get(i)).stop();
+ }
+ m_dependencies.clear();
+ }
+
+ /**
+ * Configure method. Creates managed dependencies.
+ * @param meta the component type metadata.
+ * @param dictionary the instance configuration.
+ * @throws ConfigurationException if the dependency is not configured correctly
+ * @see org.apache.felix.ipojo.Handler#configure(org.apache.felix.ipojo.metadata.Element, java.util.Dictionary)
+ */
+ public void configure(Element meta, Dictionary dictionary) throws ConfigurationException {
+ PojoMetadata manipulation = getFactory().getPojoMetadata();
+ Element[] deps = meta.getElements("requires", NAMESPACE);
+
+ // Also check with temporal is no requires.
+ if (deps == null || deps.length == 0) {
+ deps = meta.getElements("temporal", NAMESPACE);
+ }
+
+ // Get instance filters.
+ Dictionary filtersConfiguration = getRequiresFilters(dictionary.get("temporal.filters"));
+ if(filtersConfiguration == null || filtersConfiguration.isEmpty()) {
+ // Fall back on the Requires handler configuration, if any
+ filtersConfiguration = getRequiresFilters(dictionary.get("requires.filters"));
+ }
+ // Get from filters if any.
+ Dictionary fromConfiguration = getRequiresFilters(dictionary.get("temporal.from"));
+ if(fromConfiguration == null || fromConfiguration.isEmpty()) {
+ // Fall back on the Requires handler configuration, if any
+ fromConfiguration = getRequiresFilters(dictionary.get("requires.from"));
+ }
+
+
+ for (int i = 0; i < deps.length; i++) {
+ if (!deps[i].containsAttribute("field") || m_dependencies.contains(deps[i].getAttribute("field"))) {
+ error("One temporal dependency must be attached to a field or the field is already used");
+ return;
+ }
+ String field = deps[i].getAttribute("field");
+
+ String id = field;
+ if (deps[i].containsAttribute("id")) {
+ id = deps[i].getAttribute("id");
+ }
+
+ FieldMetadata fieldmeta = manipulation.getField(field);
+ if (fieldmeta == null) {
+ error("The field " + field + " does not exist in the class " + getInstanceManager().getClassName());
+ return;
+ }
+
+ boolean agg = false;
+ boolean collection = false;
+ String spec = fieldmeta.getFieldType();
+ if (spec.endsWith("[]")) {
+ agg = true;
+ spec = spec.substring(0, spec.length() - 2);
+ } else if (Collection.class.getName().equals(spec)) {
+ agg = true;
+ collection = true;
+ // Collection detected. Check for the specification attribute
+ spec = deps[i].getAttribute("specification");
+ if (spec == null) {
+ error("A dependency injected inside a Collection must contain the 'specification' attribute");
+ }
+ }
+
+ // Determine the filter
+ String fil = deps[i].getAttribute("filter");
+ // Override the filter if filter configuration if available in the instance configuration
+ if (filtersConfiguration != null && id != null && filtersConfiguration.get(id) != null) {
+ fil = (String) filtersConfiguration.get(id);
+ }
+
+ // Check the from attribute
+ String from = deps[i].getAttribute("from");
+ if (fromConfiguration != null && id != null && fromConfiguration.get(id) != null) {
+ from = (String) fromConfiguration.get(id);
+ }
+
+ if (from != null) {
+ String fromFilter = "(|(instance.name=" + from + ")(service.pid=" + from + "))";
+ if (agg) {
+ warn("The 'from' attribute is incompatible with aggregate requirements: only one provider will " +
+ "match : " + fromFilter);
+ }
+ if (fil != null) {
+ fil = "(&" + fromFilter + fil + ")"; // Append the two filters
+ } else {
+ fil = fromFilter;
+ }
+ }
+
+ Filter filter = null;
+ if (fil != null) {
+ try {
+ filter = getInstanceManager().getContext().createFilter(fil);
+ } catch (InvalidSyntaxException e) {
+ throw new ConfigurationException("A requirement filter is invalid : " + filter + " - " + e.getMessage());
+ }
+ }
+
+ String prox = deps[i].getAttribute("proxy");
+ // Use proxy by default except for array:
+ boolean proxy = prox == null || prox.equals("true");
+
+ if (prox == null && proxy) { // Proxy set because of the default.
+ if (agg && ! collection) { // Aggregate and array
+ proxy = false;
+ }
+ }
+
+ if (proxy && agg) {
+ if (! collection) {
+ error("Proxied aggregate temporal dependencies cannot be an array. Only collections are supported");
+ }
+ }
+
+ long timeout = DEFAULT_TIMEOUT;
+ if (deps[i].containsAttribute("timeout")) {
+ String to = deps[i].getAttribute("timeout");
+ if (to.equalsIgnoreCase("infinite") || to.equalsIgnoreCase("-1")) {
+ timeout = Long.MAX_VALUE; // Infinite wait time ...
+ } else {
+ timeout = new Long(deps[i].getAttribute("timeout")).longValue();
+ }
+ }
+
+ int policy = NO_POLICY;
+ String di = null;
+ String onTimeout = deps[i].getAttribute("onTimeout");
+ if (onTimeout != null) {
+ if (onTimeout.equalsIgnoreCase("nullable")) {
+ policy = NULLABLE;
+ } else if (onTimeout.equalsIgnoreCase("empty-array") || onTimeout.equalsIgnoreCase("empty")) {
+ policy = EMPTY;
+ if (! agg) {
+ // The empty array policy can only be used on aggregate dependencies
+ error("Cannot use the empty array policy for " + field + " : non aggregate dependency.");
+ }
+ } else if (onTimeout.equalsIgnoreCase("null")) {
+ policy = NULL;
+ } else if (onTimeout.length() > 0) {
+ di = onTimeout;
+ policy = DEFAULT_IMPLEMENTATION;
+ }
+ }
+
+ Class specification = DependencyModel.loadSpecification(spec, getInstanceManager().getContext());
+ TemporalDependency dep = new TemporalDependency(specification, agg, collection, proxy, filter, getInstanceManager().getContext(), timeout, policy, di, this);
+ m_dependencies.add(dep);
+
+ if (! proxy) { // Register method interceptor only if are not a proxy
+ MethodMetadata[] methods = manipulation.getMethods();
+ for (int k = 0; k < methods.length; k++) {
+ getInstanceManager().register(methods[k], dep);
+ }
+ }
+
+ getInstanceManager().register(fieldmeta, dep);
+ }
+ }
+
+ /**
+ * Gets the requires filter configuration from the given object.
+ * The given object must come from the instance configuration.
+ * This method was made to fix FELIX-2688. It supports filter configuration using
+ * an array:
+ * <code>{"myFirstDep", "(property1=value1)", "mySecondDep", "(property2=value2)"});</code>
+ *
+ * Copied from DependencyHandler#getRequiresFilters(Object)
+ *
+ * @param requiresFiltersValue the value contained in the instance
+ * configuration.
+ * @return the dictionary. If the object in already a dictionary, just returns it,
+ * if it's an array, builds the dictionary.
+ * @throws ConfigurationException the dictionary cannot be built
+ */
+ private Dictionary getRequiresFilters(Object requiresFiltersValue)
+ throws ConfigurationException {
+ if (requiresFiltersValue != null
+ && requiresFiltersValue.getClass().isArray()) {
+ String[] filtersArray = (String[]) requiresFiltersValue;
+ if (filtersArray.length % 2 != 0) {
+ throw new ConfigurationException(
+ "A requirement filter is invalid : "
+ + requiresFiltersValue);
+ }
+ Dictionary requiresFilters = new Hashtable();
+ for (int i = 0; i < filtersArray.length; i += 2) {
+ requiresFilters.put(filtersArray[i], filtersArray[i + 1]);
+ }
+ return requiresFilters;
+ }
+
+ return (Dictionary) requiresFiltersValue;
+ }
+
+ /**
+ * Nothing to do.
+ * A temporal dependency is always valid.
+ * @param dependencymodel dependency.
+ * @see org.apache.felix.ipojo.util.DependencyStateListener#invalidate(org.apache.felix.ipojo.util.DependencyModel)
+ */
+ public void invalidate(DependencyModel dependencymodel) { }
+
+ /**
+ * Nothing to do.
+ * A temporal dependency is always valid.
+ * @param dependencymodel dependency.
+ * @see org.apache.felix.ipojo.util.DependencyStateListener#validate(org.apache.felix.ipojo.util.DependencyModel)
+ */
+ public void validate(DependencyModel dependencymodel) { }
+
+
+}
Added: felix/trunk/ipojo/handler/temporal/temporal-dependency-handler/src/main/resources/metadata.xml
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/handler/temporal/temporal-dependency-handler/src/main/resources/metadata.xml?rev=1451167&view=auto
==============================================================================
--- felix/trunk/ipojo/handler/temporal/temporal-dependency-handler/src/main/resources/metadata.xml (added)
+++ felix/trunk/ipojo/handler/temporal/temporal-dependency-handler/src/main/resources/metadata.xml Thu Feb 28 10:27:21 2013
@@ -0,0 +1,28 @@
+<!--
+ 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.
+-->
+<ipojo>
+ <handler
+ classname="org.apache.felix.ipojo.handler.temporal.TemporalHandler"
+ name="requires" namespace="org.apache.felix.ipojo.handler.temporal">
+ </handler>
+ <handler
+ classname="org.apache.felix.ipojo.handler.temporal.TemporalHandler"
+ name="temporal" namespace="org.apache.felix.ipojo.handler.temporal">
+ </handler>
+</ipojo>
\ No newline at end of file
Added: felix/trunk/ipojo/handler/temporal/temporal-dependency-handler/src/main/resources/temporal.xsd
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/handler/temporal/temporal-dependency-handler/src/main/resources/temporal.xsd?rev=1451167&view=auto
==============================================================================
--- felix/trunk/ipojo/handler/temporal/temporal-dependency-handler/src/main/resources/temporal.xsd (added)
+++ felix/trunk/ipojo/handler/temporal/temporal-dependency-handler/src/main/resources/temporal.xsd Thu Feb 28 10:27:21 2013
@@ -0,0 +1,63 @@
+<!--
+ 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.
+-->
+<xs:schema targetNamespace="org.apache.felix.ipojo.handler.temporal"
+ xmlns="org.apache.felix.ipojo.handler.temporal"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified">
+ <xs:element name="requires" type="TemporalServiceDependencyType"></xs:element>
+ <xs:element name="temporal" type="TemporalServiceDependencyType"></xs:element>
+
+
+ <xs:complexType name="TemporalServiceDependencyType">
+
+ <xs:annotation>
+ <xs:documentation>Description of a temporal dependency.</xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="field" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>The implementation field supporting the dependency.</xs:documentation>
+ </xs:annotation></xs:attribute>
+ <xs:attribute name="id" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>The dependency id</xs:documentation>
+ </xs:annotation></xs:attribute>
+ <xs:attribute name="filter" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Filter use to discover matching filter.</xs:documentation></xs:annotation></xs:attribute>
+ <xs:attribute name="timeout" type="xs:int" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the timeout after which the onTimeout policy is executed. The value is the time in ms to wait. -1 is used to indicate an infinite wait.</xs:documentation>
+ </xs:annotation></xs:attribute>
+ <xs:attribute name="onTimeout" use="optional" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>Specifies the onTimeout policy. This determines the object to inject when the service stills unavailable when the timeout expires. Several values are supported: 'nullable' means that a Nullable object will be injected, 'empty-array' injects an empty array (only for aggregate dependency), 'null' injects Null, any other value are interpreted as the default implementation class to use. If the onTimetout attribute is not specified, a RuntimeException is thrown when the timeout is reached.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="proxy" use="optional" type="xs:boolean">
+ <xs:annotation>
+ <xs:documentation>Enables or Disables the proxy injection</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="specification" use="optional" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>Specifies the looked service specification. This attribute is mandatory when injecting in a Collection</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+</xs:schema>
\ No newline at end of file