Removed TemporalServiceDependency, but added a timeout attribute in the ServiceDependency annotation

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@947788 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/dependency/ServiceDependency.java b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/dependency/ServiceDependency.java
index 85bb686..e265a15 100644
--- a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/dependency/ServiceDependency.java
+++ b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/dependency/ServiceDependency.java
@@ -66,4 +66,42 @@
      * The callback method to invoke when the service is lost.
      */
     String removed() default "";
+    
+    /** 
+     * The max time in millis to wait for the dependency availability. 
+     * Specifying a positive number allow to block the caller thread between service updates. Only
+     * useful for required stateless dependencies that can be replaced transparently.
+     * A Dynamic Proxy is used to wrap the actual service dependency (which must be an interface). 
+     * When the dependency goes away, an attempt is made to replace it with another one which satisfies 
+     * the service dependency criteria. If no service replacement is available, then any method invocation 
+     * (through the dynamic proxy) will block during a configurable timeout. On timeout, an unchecked 
+     * <code>IllegalStateException</code> exception is raised (but the service is not deactivated).<p>
+     * Notice that the changed/removed callbacks are not used when the timeout parameter is > -1.
+     * <p> 
+     * 
+     * -1 means no timeout at all (default). 0 means that invocation on a missing service will fail 
+     * immediately. A positive number represents the max timeout in millisends to wait for the service availability.
+     * 
+     * <p> Sample Code:<p>
+     * <blockquote><pre>
+     * &#64;Service
+     * class MyServer implements Runnable {
+     *   &#64;ServiceDependency(timeout=15000)
+     *   MyDependency _dependency;.
+     *   
+     *   &#64;Start
+     *   void start() {
+     *     (new Thread(this)).start();
+     *   }
+     *   
+     *   public void run() {
+     *     try {
+     *       _dependency.doWork();
+     *     } catch (IllegalStateException e) {
+     *       t.printStackTrace();
+     *     }
+     *   }   
+     * </pre></blockquote>
+     */
+    long timeout() default -1;
 }
diff --git a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/dependency/TemporalServiceDependency.java b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/dependency/TemporalServiceDependency.java
deleted file mode 100644
index e445adb..0000000
--- a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/dependency/TemporalServiceDependency.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * 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.dm.annotation.api.dependency;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Annotates a method or a field for injecting a Temporal Service Dependency.
- * A Temporal Service dependency can block the caller thread between service updates. Only
- * useful for required stateless dependencies that can be replaced transparently.
- * A Dynamic Proxy is used to wrap the actual service dependency. When the dependency goes 
- * away, an attempt is made to replace it with another one which satisfies the service dependency 
- * criteria. If no service replacement is available, then any method invocation (through the 
- * dynamic proxy) will block during a configurable timeout. On timeout, an unchecked 
- * <code>IllegalStateException</code> exception is raised (but the service is not deactivated).<p>
- * 
- * <b>Only supports required dependencies</b>
- *
- * <p> Sample Code:<p>
- * <blockquote>
- * 
- * <pre>
- * &#64;Service
- * class MyServer implements Runnable {
- *   &#64;TemporalServiceDependency(timeout=15000)
- *   MyDependency _dependency;.
- *   
- *   &#64;Start
- *   void start() {
- *     (new Thread(this)).start();
- *   }
- *   
- *   public void run() {
- *     try {
- *       _dependency.doWork();
- *     } catch (IllegalStateException e) {
- *       t.printStackTrace();
- *     }
- *   }   
- * </pre>
- * 
- * </blockquote>
- */
-@Retention(RetentionPolicy.CLASS)
-@Target( { ElementType.METHOD, ElementType.FIELD })
-public @interface TemporalServiceDependency
-{
-    /**
-     * Sets the timeout for this temporal dependency. Specifying a timeout value of zero means that there is no timeout period,
-     * and an invocation on a missing service will fail immediately.
-     * 
-     * @param timeout the dependency timeout value greater or equals to 0
-     * @throws IllegalArgumentException if the timeout is negative
-     * @return this temporal dependency
-     */
-    long timeout() default 30000L;
-
-    /**
-     * Returns the Service dependency type (by default, the type is method parameter type).
-     * @return the Service dependency type.
-     */
-    Class<?> service() default Object.class;
-
-    /**
-     * Returns the Service dependency OSGi filter.
-     * @return The Service dependency filter.
-     */
-    String filter() default "";
-
-    /**
-     * Returns the class for the default implementation, if the dependency is not available.
-     * @return The default class used when the dependency is not available.
-     */
-    Class<?> defaultImpl() default Object.class;
-
-    /**
-     * Returns the callback method to be invoked when the service is available. This attribute is only meaningful when 
-     * the annotation is applied on a class field.
-     */
-    String added() default "";
-}
diff --git a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java
index 83d3a48..c1b57fe 100644
--- a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java
+++ b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java
@@ -42,7 +42,6 @@
 import org.apache.felix.dm.annotation.api.dependency.ConfigurationDependency;
 import org.apache.felix.dm.annotation.api.dependency.ResourceDependency;
 import org.apache.felix.dm.annotation.api.dependency.ServiceDependency;
-import org.apache.felix.dm.annotation.api.dependency.TemporalServiceDependency;
 import org.osgi.framework.Bundle;
 
 import aQute.lib.osgi.Annotation;
@@ -68,8 +67,6 @@
         + ServiceDependency.class.getName().replace('.', '/') + ";";
     private final static String A_CONFIGURATION_DEPENDENCY = "L"
         + ConfigurationDependency.class.getName().replace('.', '/') + ";";
-    private final static String A_TEMPORAL_SERVICE_DEPENDENCY = "L"
-        + TemporalServiceDependency.class.getName().replace('.', '/') + ";";
     private final static String A_BUNDLE_DEPENDENCY = "L"
         + BundleDependency.class.getName().replace('.', '/') + ";";
     private final static String A_RESOURCE_DEPENDENCY = "L"
@@ -239,16 +236,12 @@
         }
         else if (annotation.getName().equals(A_SERVICE_DEP))
         {
-            parseServiceDependencyAnnotation(annotation, false);
+            parseServiceDependencyAnnotation(annotation);
         }
         else if (annotation.getName().equals(A_CONFIGURATION_DEPENDENCY))
         {
             parseConfigurationDependencyAnnotation(annotation);
         }
-        else if (annotation.getName().equals(A_TEMPORAL_SERVICE_DEPENDENCY))
-        {
-            parseServiceDependencyAnnotation(annotation, true);
-        }
         else if (annotation.getName().equals(A_BUNDLE_DEPENDENCY))
         {
             parseBundleDependencyAnnotation(annotation);
@@ -317,13 +310,12 @@
     }
 
     /**
-     * Parses a ServiceDependency or a TemporalServiceDependency Annotation.
+     * Parses a ServiceDependency Annotation.
      * @param annotation the ServiceDependency Annotation.
      */
-    private void parseServiceDependencyAnnotation(Annotation annotation, boolean temporal)
+    private void parseServiceDependencyAnnotation(Annotation annotation)
     {
-        EntryWriter writer = new EntryWriter(temporal ? EntryType.TemporalServiceDependency
-            : EntryType.ServiceDependency);
+        EntryWriter writer = new EntryWriter(EntryType.ServiceDependency);
         m_writers.add(writer);
 
         // service attribute
@@ -365,22 +357,22 @@
         // added callback
         writer.putString(annotation, EntryParam.added, (!m_isField) ? m_method : null);
 
-        if (temporal)
+        // timeout parameter
+        writer.putString(annotation, EntryParam.timeout, null);
+        Long t = (Long) annotation.get(EntryParam.timeout.toString());
+        if (t != null && t.longValue() < -1)
         {
-            // timeout attribute (only valid if parsing a temporal service dependency)
-            writer.putString(annotation, EntryParam.timeout, null);
+            throw new IllegalArgumentException("Invalid timeout value " + t + " in ServiceDependency annotation in class " + m_className);
         }
-        else
-        {
-            // required attribute (not valid if parsing a temporal service dependency)
-            writer.putString(annotation, EntryParam.required, null);
+        
+        // required attribute (not valid if parsing a temporal service dependency)
+        writer.putString(annotation, EntryParam.required, null);
 
-            // changed callback
-            writer.putString(annotation, EntryParam.changed, null);
+        // changed callback
+        writer.putString(annotation, EntryParam.changed, null);
 
-            // removed callback
-            writer.putString(annotation, EntryParam.removed, null);
-        }
+        // removed callback
+        writer.putString(annotation, EntryParam.removed, null);       
     }
 
     /**
diff --git a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/EntryType.java b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/EntryType.java
index bdbd005..4e0997d 100644
--- a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/EntryType.java
+++ b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/EntryType.java
@@ -12,7 +12,6 @@
     ResourceAdapterService,
     FactoryConfigurationAdapterService,
     ServiceDependency, 
-    TemporalServiceDependency, 
     ConfigurationDependency,
     BundleDependency,
     ResourceDependency,
diff --git a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/DependencyBuilder.java b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/DependencyBuilder.java
index 42fdf89..1b206c3 100644
--- a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/DependencyBuilder.java
+++ b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/DependencyBuilder.java
@@ -72,11 +72,7 @@
         switch (type)
         {
             case ServiceDependency:
-                dp = createServiceDependency(b, dm, false, instanceBound);
-                break;
-
-            case TemporalServiceDependency:
-                dp = createServiceDependency(b, dm, true, instanceBound);
+                dp = createServiceDependency(b, dm, instanceBound);
                 break;
 
             case ConfigurationDependency:
@@ -94,8 +90,7 @@
         return dp;
     }
 
-    private Dependency createServiceDependency(Bundle b, DependencyManager dm, boolean temporal,
-        boolean instanceBound)
+    private Dependency createServiceDependency(Bundle b, DependencyManager dm, boolean instanceBound)
         throws ClassNotFoundException
     {
         String service = m_metaData.getString(Params.service);
@@ -105,24 +100,24 @@
         Class<?> defaultServiceImplClass =
             (defaultServiceImpl != null) ? b.loadClass(defaultServiceImpl) : null;
         String added = m_metaData.getString(Params.added, null);
-        String changed = temporal ? null : m_metaData.getString(Params.changed, null);
-        String removed = temporal ? null : m_metaData.getString(Params.removed, null);
+        long timeout = m_metaData.getLong(Params.timeout, -1L);
+        String changed = timeout != -1 ? null : m_metaData.getString(Params.changed, null);
+        String removed = timeout != -1 ? null : m_metaData.getString(Params.removed, null);
         String autoConfigField = m_metaData.getString(Params.autoConfig, null);
         boolean required = "true".equals(m_metaData.getString(Params.required, "true"));
-        String timeout = m_metaData.getString(Params.timeout, null);
 
-        Dependency dp = createServiceDependency(dm, temporal, serviceClass,
+        Dependency dp = createServiceDependency(dm, serviceClass,
             serviceFilter, defaultServiceImplClass, added, changed,
             removed, autoConfigField, timeout, required, instanceBound);
         return dp;
     }
 
-    private Dependency createServiceDependency(DependencyManager dm, boolean temporal,
-        Class<?> serviceClass, String serviceFilter, Class<?> defaultServiceImplClass, String added,
-        String changed, String removed, String autoConfigField, String timeout, boolean required,
+    private Dependency createServiceDependency(DependencyManager dm, Class<?> serviceClass, 
+        String serviceFilter, Class<?> defaultServiceImplClass, String added,
+        String changed, String removed, String autoConfigField, long timeout, boolean required,
         boolean instanceBound)
     {
-        ServiceDependency sd = temporal ? dm.createTemporalServiceDependency()
+        ServiceDependency sd = timeout != -1 ? dm.createTemporalServiceDependency()
             : dm.createServiceDependency();
         sd.setService(serviceClass, serviceFilter);
         if (defaultServiceImplClass != null)
@@ -134,13 +129,9 @@
         {
             sd.setAutoConfig(autoConfigField);
         }
-        if (temporal)
+        if (timeout != -1)
         {
-            // Set the timeout value for a temporal service dependency
-            if (timeout != null)
-            {
-                ((TemporalServiceDependency) sd).setTimeout(Long.parseLong(timeout));
-            }
+            ((TemporalServiceDependency) sd).setTimeout(timeout);
             // Set required flag (always true for a temporal dependency)
             sd.setRequired(true);
         }
diff --git a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/JSONMetaData.java b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/JSONMetaData.java
index 7fc7054..217a01e 100644
--- a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/JSONMetaData.java
+++ b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/JSONMetaData.java
@@ -171,6 +171,51 @@
         }
     }
 
+    public long getLong(Params key)
+    {
+        String value = getString(key, null);
+        if (value != null)
+        {
+            try
+            {
+                return Long.parseLong(value);
+            }
+            catch (NumberFormatException e)
+            {
+                throw new IllegalArgumentException("parameter " + key
+                    + " is not a long value: "
+                    + value);
+            }
+        }
+        else
+        {
+            throw new IllegalArgumentException("missing " + key
+                + " parameter from annotation");
+        }
+    }
+
+    public long getLong(Params key, long def)
+    {
+        String value = getString(key, null);
+        if (value != null)
+        {
+            try
+            {
+                return Long.parseLong(value);
+            }
+            catch (NumberFormatException e)
+            {
+                throw new IllegalArgumentException("parameter " + key
+                    + " is not a long value: "
+                    + value);
+            }
+        }
+        else
+        {
+            return def;
+        }
+    }
+
     public String[] getStrings(Params key)
     {
         Object array = m_metadata.get(key.toString());
diff --git a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/MetaData.java b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/MetaData.java
index 7c56a30..166a006 100644
--- a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/MetaData.java
+++ b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/MetaData.java
@@ -44,6 +44,16 @@
      * Returns a String descriptor entry parameter value.
      */
     int getInt(Params key, int def);
+    
+    /**
+     * Returns a String descriptor entry parameter value.
+     */
+    long getLong(Params key);
+
+    /**
+     * Returns a String descriptor entry parameter value.
+     */
+    long getLong(Params key, long def);
 
     /**
      * Returns a String array descriptor entry parameter value.
diff --git a/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/temporal/TemporalTest.java b/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/temporal/TemporalTest.java
index 803f3a6..b6288d7 100644
--- a/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/temporal/TemporalTest.java
+++ b/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/temporal/TemporalTest.java
@@ -22,7 +22,6 @@
 import org.apache.felix.dm.annotation.api.Start;
 import org.apache.felix.dm.annotation.api.Stop;
 import org.apache.felix.dm.annotation.api.dependency.ServiceDependency;
-import org.apache.felix.dm.annotation.api.dependency.TemporalServiceDependency;
 import org.apache.felix.dm.test.bundle.annotation.sequencer.Sequencer;
 
 /**
@@ -36,7 +35,7 @@
     @ServiceDependency
     Sequencer m_sequencer;
 
-    @TemporalServiceDependency(timeout = 1000L, filter = "(test=temporal)")
+    @ServiceDependency(timeout = 1000L, filter = "(test=temporal)")
     Runnable m_service;
 
     @Start