You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ma...@apache.org on 2008/01/30 17:46:39 UTC

svn commit: r616813 [3/9] - in /felix/trunk/deploymentadmin: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/felix/ src/main/java/org/apache/felix/deploymentadmin/ src/main/java/org/apache/felix/de...

Added: felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/StopBundleCommand.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/StopBundleCommand.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/StopBundleCommand.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/StopBundleCommand.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,76 @@
+/*
+ * 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.deploymentadmin.spi;
+
+import org.apache.felix.deploymentadmin.AbstractDeploymentPackage;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.service.deploymentadmin.BundleInfo;
+import org.osgi.service.deploymentadmin.DeploymentException;
+import org.osgi.service.log.LogService;
+
+/**
+ * Command that stops all bundles described in the target deployment package of a deployment session.
+ */
+public class StopBundleCommand extends Command {
+
+    public void execute(DeploymentSessionImpl session) throws DeploymentException {
+        AbstractDeploymentPackage target = session.getTargetAbstractDeploymentPackage();
+        BundleInfo[] bundleInfos = target.getOrderedBundleInfos();
+        for (int i = 0; i < bundleInfos.length; i++) {
+            if (isCancelled()) {
+                throw new DeploymentException(DeploymentException.CODE_CANCELLED);
+            }
+            Bundle bundle = target.getBundle(bundleInfos[i].getSymbolicName());
+            if (bundle != null) {
+                addRollback(new StartBundleRunnable(bundle));
+                try {
+                    bundle.stop();
+                }
+                catch (BundleException e) {
+                	session.getLog().log(LogService.LOG_WARNING, "Could not stop bundle '" + bundle.getSymbolicName() + "'", e);
+                }
+            }
+            else {
+            	session.getLog().log(LogService.LOG_WARNING, "Could not stop bundle '" + bundleInfos[i].getSymbolicName() + "' because it was not defined int he framework");
+            }
+        }
+    }
+
+    private class StartBundleRunnable implements Runnable {
+
+        private final Bundle m_bundle;
+
+        public StartBundleRunnable(Bundle bundle) {
+            m_bundle = bundle;
+        }
+
+        public void run() {
+            try {
+                m_bundle.start();
+            }
+            catch (BundleException e) {
+                // TODO: log this
+                e.printStackTrace();
+            }
+        }
+
+    }
+}
+

Added: felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/UpdateCommand.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/UpdateCommand.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/UpdateCommand.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/spi/UpdateCommand.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,168 @@
+/*
+ * 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.deploymentadmin.spi;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.felix.deploymentadmin.AbstractDeploymentPackage;
+import org.apache.felix.deploymentadmin.AbstractInfo;
+import org.apache.felix.deploymentadmin.BundleInfoImpl;
+import org.apache.felix.deploymentadmin.Constants;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Version;
+import org.osgi.service.deploymentadmin.DeploymentException;
+
+/**
+ * Command that installs all bundles described in the source deployment package of a deployment
+ * session. If a bundle was already defined in the target deployment package of the same session
+ * it is updated, otherwise the bundle is simply installed.
+ */
+public class UpdateCommand extends Command {
+
+    public void execute(DeploymentSessionImpl session) throws DeploymentException {
+        AbstractDeploymentPackage source = session.getSourceAbstractDeploymentPackage();
+        AbstractDeploymentPackage targetPackage = session.getTargetAbstractDeploymentPackage();
+        BundleContext context = session.getBundleContext();
+
+        Map expectedBundles = new HashMap();
+        AbstractInfo[] bundleInfos = (AbstractInfo[]) source.getBundleInfos();
+        for (int i = 0; i < bundleInfos.length; i++) {
+            AbstractInfo bundleInfo = bundleInfos[i];
+            if(!bundleInfo.isMissing()) {
+                expectedBundles.put(bundleInfo.getPath(), bundleInfo);
+            }
+        }
+
+        try {
+            for (AbstractInfo entry = source.getNextEntry(); (entry != null) && (!expectedBundles.isEmpty()); entry = source.getNextEntry()) {
+                String name = entry.getPath();
+                if (!expectedBundles.containsKey(name)) {
+                    throw new DeploymentException(DeploymentException.CODE_OTHER_ERROR, "Resource '" + name + "' is not described in the manifest.");
+                }
+
+                BundleInfoImpl bundleInfo = (BundleInfoImpl) expectedBundles.remove(name);
+                Bundle bundle = source.getBundle(bundleInfo.getSymbolicName());
+                try {
+                    if (bundle == null) {
+                        // new bundle, install it
+                        bundle = context.installBundle(Constants.BUNDLE_LOCATION_PREFIX + bundleInfo.getSymbolicName(), new BundleInputStream(source.getCurrentEntryStream()));
+                        addRollback(new UninstallBundleRunnable(bundle));
+                    } else {
+                        // existing bundle, update it
+                        Version sourceVersion = bundleInfo.getVersion();
+                        Version targetVersion = Version.parseVersion((String) bundle.getHeaders().get(org.osgi.framework.Constants.BUNDLE_VERSION));
+                        if (!sourceVersion.equals(targetVersion)) {
+                            bundle.update(new BundleInputStream(source.getCurrentEntryStream()));
+                            addRollback(new UpdateBundleRunnable(bundle, targetPackage, bundleInfo.getSymbolicName()));
+                        }
+                    }
+                }
+                catch (BundleException be) {
+                    if (isCancelled()) {
+                        return;
+                    }
+                    throw new DeploymentException(DeploymentException.CODE_OTHER_ERROR, "Could not install new bundle '" + name + "'", be);
+                }
+                if (!bundle.getSymbolicName().equals(bundleInfo.getSymbolicName()) || !Version.parseVersion((String)bundle.getHeaders().get(org.osgi.framework.Constants.BUNDLE_VERSION)).equals(bundleInfo.getVersion())) {
+                    throw new DeploymentException(DeploymentException.CODE_OTHER_ERROR, "Installed/updated bundle version and/or symbolicnames do not match what was installed/updated");
+                }
+            }
+        }
+        catch (IOException e) {
+            throw new DeploymentException(DeploymentException.CODE_OTHER_ERROR, "Problem while reading stream", e);
+        }
+    }
+
+    private static class UninstallBundleRunnable implements Runnable {
+
+        private final Bundle m_bundle;
+
+        public UninstallBundleRunnable(Bundle bundle) {
+            m_bundle = bundle;
+        }
+
+        public void run() {
+            try {
+                m_bundle.uninstall();
+            }
+            catch (BundleException e) {
+                // TODO: log this
+                e.printStackTrace();
+            }
+        }
+    }
+
+    private static class UpdateBundleRunnable implements Runnable {
+
+        private final Bundle m_bundle;
+        private final AbstractDeploymentPackage m_targetPackage;
+        private final String m_symbolicName;
+
+        public UpdateBundleRunnable(Bundle bundle, AbstractDeploymentPackage targetPackage, String symbolicName) {
+            m_bundle = bundle;
+            m_targetPackage = targetPackage;
+            m_symbolicName = symbolicName;
+        }
+
+        public void run() {
+            try {
+                m_bundle.update(m_targetPackage.getBundleStream(m_symbolicName));
+            }
+            catch (Exception e) {
+                // TODO: log this
+                e.printStackTrace();
+            }
+        }
+    }
+
+    private final class BundleInputStream extends InputStream {
+        private final InputStream m_inputStream;
+
+        private BundleInputStream(InputStream jarInputStream) {
+            m_inputStream = jarInputStream;
+        }
+
+        public int read() throws IOException {
+            checkCancel();
+            return m_inputStream.read();
+        }
+
+        public int read(byte[] buffer) throws IOException {
+            checkCancel();
+            return m_inputStream.read(buffer);
+        }
+
+        public int read(byte[] buffer, int off, int len) throws IOException {
+            checkCancel();
+            return m_inputStream.read(buffer, off, len);
+        }
+
+        private void checkCancel() throws IOException {
+            if (isCancelled()) {
+                throw new IOException("Stream was cancelled");
+            }
+        }
+    }
+
+}

Added: felix/trunk/deploymentadmin/src/main/java/org/osgi/application/ApplicationContext.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/osgi/application/ApplicationContext.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/osgi/application/ApplicationContext.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/osgi/application/ApplicationContext.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,355 @@
+/*
+ * $Header: /cvshome/build/org.osgi.application/src/org/osgi/application/ApplicationContext.java,v 1.15 2006/07/11 13:19:02 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2005, 2006). All Rights Reserved.
+ * 
+ * Licensed 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.osgi.application;
+
+import java.util.Dictionary;
+import java.util.Map;
+
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+
+
+/**
+ * <code>ApplicationContext</code> is the access point for an OSGi-aware
+ * application to the features of the OSGi Service Platform. Each application
+ * instance will have its own <code>ApplicationContext</code> instance, which
+ * will not be reused after destorying the corresponding application instace.
+ * <p>
+ * Application instances can obtain their <code>ApplicationContext</code>
+ * using the {@link Framework#getApplicationContext} method.
+ * <p>
+ * The lifecycle of an <code>ApplicationContext</code> instance is bound to
+ * the lifecycle of the corresponding application instance. The 
+ * <code>ApplicationContext</code> becomes available when the application is
+ * started and it is invalidated when the application instance is stopped (i.e.
+ * the "stop" method of the application activator object returned).
+ * All method calls (except {@link #getApplicationId()} and 
+ * {@link #getInstanceId()}) to an invalidated context object result an 
+ * <code>IllegalStateException</code>.
+ * 
+ * @see org.osgi.application.Framework
+ */
+public interface ApplicationContext {
+
+    /**
+     * Adds the specified {@link ApplicationServiceListener} object to this context
+     * application instance's list of listeners. The specified <code>referenceName</code> is a 
+     * reference name specified in the descriptor of the corresponding application. The registered
+     * <code>listener> will only receive the {@link ApplicationServiceEvent}s realted to the referred service.
+     * <p>
+     * If the <code>listener</code> was already added, calling this method will overwrite the previous
+     * registration.
+     * <p>
+     * 
+     * @param listener
+     *            The {@link org.osgi.application.ApplicationServiceListener} to be added. It must
+     *            not be <code>null</code>
+     * @param referenceName the reference name of a service from the descriptor of the corresponding
+     *            application. It must not be <code>null</code>.
+     * @throws java.lang.IllegalStateException
+     *             If this context application instance has stopped.
+     * @throws java.lang.NullPointerException If <code>listener</code> or <code>referenceName</code>
+     *             is <code>null</code>      
+     * @throws java.lang.IllegalArgumentException If there is no service in the
+     *             application descriptor with the specified <code>referenceName</code>.
+     */
+    public void addServiceListener(ApplicationServiceListener listener, String referenceName) throws java.lang.IllegalArgumentException;
+
+    /**
+     * Adds the specified {@link ApplicationServiceListener} object to this context
+     * application instance's list of listeners. The <code>referenceNames</code> parameter is an 
+     * array of reference name specified in the descriptor of the corresponding application. The registered
+     * <code>listener> will only receive the {@link ApplicationServiceEvent}s realted to the referred 
+     * services.
+     * <p>
+     * If the <code>listener</code> was already added, calling this method will overwrite the previous
+     * registration.
+     * <p>
+     * 
+     * @param listener
+     *            The {@link org.osgi.application.ApplicationServiceListener} to be added. It must not
+     *            be <code>null</code>
+     * @param referenceNames and array of service reference names from the descriptor of the corresponding
+     *            application. It must not be <code>null</code> and it must not be empty.
+     * @throws java.lang.IllegalStateException
+     *             If this context application instance has stopped.
+     * @throws java.lang.NullPointerException If <code>listener</code> or <code>referenceNames</code>
+     *             is <code>null</code>      
+     * @throws java.lang.IllegalArgumentException If <code>referenceNames</code> array is empty or it 
+     *    contains unknown references
+     */
+    public void addServiceListener(ApplicationServiceListener listener, String[] referenceNames) throws java.lang.IllegalArgumentException;
+
+    /**
+     * Removes the specified {@link org.osgi.application.ApplicationServiceListener} object from this
+     * context application instances's list of listeners.
+     * <p>
+     * If <code>listener</code> is not contained in this context application
+     * instance's list of listeners, this method does nothing.
+     * 
+     * @param listener
+     *            The {@link org.osgi.application.ApplicationServiceListener} object to be removed.
+     * @throws java.lang.IllegalStateException
+     *             If this context application instance has stopped.
+     */
+    public void removeServiceListener(ApplicationServiceListener listener);
+    
+    /**
+     * This method returns the identifier of the corresponding application instace.
+     * This identifier is guarateed to be unique within the scope of the device.
+     * 
+      * Note: this method can safely be called on an invalid 
+     * <code>ApplicationContext</code> as well.
+     * 
+     * @see org.osgi.service.application.ApplicationHandle#getInstanceId()
+     * 
+     * @return the unique identifier of the corresponding application instance
+     */
+    public String getInstanceId();
+    
+    /**
+     * This method return the identifier of the correspondig application type. This identifier
+     * is the same for the different instances of the same application but it is different for
+     * different application type.
+     * <p>
+     * Note: this method can safely be called on an invalid 
+     * <code>ApplicationContext</code> as well.
+     * 
+     * @see org.osgi.service.application.ApplicationDescriptor#getApplicationId()
+     * 
+     * @return the identifier of the application type.
+     */
+    public String getApplicationId();
+
+    /**
+     * This method returns the service object for the specified
+     * <code>referenceName</code>. If the cardinality of the reference is
+     * 0..n or 1..n and multiple services are bound to the reference, the
+     * service with the highest ranking (as specified in its
+     * {@link org.osgi.framework.Constants#SERVICE_RANKING} property) is returned. If there
+     * is a tie in ranking, the service with the lowest service ID (as specified
+     * in its {@link org.osgi.framework.Constants#SERVICE_ID} property); that is, the
+     * service that was registered first is returned.
+     * 
+     * @param referenceName
+     *            The name of a reference as specified in a reference element in
+     *            this context applications's description. It must not be <code>null</code>
+     * @return A service object for the referenced service or <code>null</code>
+     *         if the reference cardinality is 0..1 or 0..n and no bound service
+     *         is available.
+     * @throws java.lang.NullPointerException If <code>referenceName</code> is <code>null</code>.
+     * @throws java.lang.IllegalArgumentException If there is no service in the
+     *             application descriptor with the specified <code>referenceName</code>.
+     * @throws java.lang.IllegalStateException
+     *             If this context application instance has stopped.
+     */
+    public Object locateService(String referenceName);
+
+    /**
+     * This method returns the service objects for the specified
+     * <code>referenceName</code>.
+     * 
+     * @param referenceName
+     *            The name of a reference as specified in a reference element in
+     *            this context applications's description. It must not be 
+     *            <code>null</code>.
+     * @return An array of service object for the referenced service or
+     *         <code>null</code> if the reference cardinality is 0..1 or 0..n
+     *         and no bound service is available.
+     * @throws java.lang.NullPointerException If <code>referenceName</code> is <code>null</code>.
+     * @throws java.lang.IllegalArgumentException If there is no service in the
+     *             application descriptor with the specified <code>referenceName</code>.
+     * @throws java.lang.IllegalStateException
+     *             If this context application instance has stopped.
+     */
+    public Object[] locateServices(String referenceName);
+    
+    /**
+     * Returns the startup parameters specified when calling the 
+     * {@link org.osgi.service.application.ApplicationDescriptor#launch}
+     * method.
+     * <p>
+     * Startup arguments can be specified as name, value pairs. The name
+     * must be of type {@link java.lang.String}, which must not be
+     * <code>null</code> or empty {@link java.lang.String} (<code>""</code>), 
+     * the value can be any object including <code>null</code>.
+     * 
+     * @return a {@link java.util.Map} containing the startup arguments. 
+     *     It can be <code>null</code>.
+     * @throws java.lang.IllegalStateException
+     *             If this context application instance has stopped.
+     */
+    public Map getStartupParameters();
+    
+    /**
+     * Application can query the service properties of a service object
+     * it is bound to. Application gets bound to a service object when
+     * it fisrt obtains a reference to the service by calling 
+     * <code>locateService</code> or <code>locateServices</code> methods.
+     * 
+     * @param serviceObject A service object the application is bound to.
+     *    It must not be null.
+     * @return The service properties associated with the specified service
+     *    object.
+     * @throws NullPointerException if the specified <code>serviceObject</code>
+     *    is <code>null</code>
+     * @throws IllegalArgumentException if the application is not
+     *    bound to the specified service object or it is not a service
+     *    object at all.
+     * @throws java.lang.IllegalStateException
+     *             If this context application instance has stopped.
+     */
+    public Map getServiceProperties(Object serviceObject);
+
+    
+    /**
+	 * Registers the specified service object with the specified properties
+	 * under the specified class names into the Framework. A
+	 * {@link org.osgi.framework.ServiceRegistration} object is returned. The
+	 * {@link org.osgi.framework.ServiceRegistration} object is for the private use of the
+	 * application registering the service and should not be shared with other
+	 * applications. The registering application is defined to be the context application.
+	 * Bundles can locate the service by using either the
+	 * {@link org.osgi.framework.BundleContext#getServiceReferences} or 
+	 * {@link org.osgi.framework.BundleContext#getServiceReference} method. Other applications
+	 * can locate this service by using {@link #locateService(String)} or {@link #locateServices(String)}
+	 * method, if they declared their dependece on the registered service.
+	 * 
+	 * <p>
+	 * An application can register a service object that implements the
+	 * {@link org.osgi.framework.ServiceFactory} interface to have more flexibility in providing
+	 * service objects to other applications or bundles.
+	 * 
+	 * <p>
+	 * The following steps are required to register a service:
+	 * <ol>
+	 * <li>If <code>service</code> is not a <code>ServiceFactory</code>,
+	 * an <code>IllegalArgumentException</code> is thrown if
+	 * <code>service</code> is not an <code>instanceof</code> all the
+	 * classes named.
+	 * <li>The Framework adds these service properties to the specified
+	 * <code>Dictionary</code> (which may be <code>null</code>): a property
+	 * named {@link org.osgi.framework.Constants#SERVICE_ID} identifying the registration number of
+	 * the service and a property named {@link org.osgi.framework.Constants#OBJECTCLASS} containing
+	 * all the specified classes. If any of these properties have already been
+	 * specified by the registering bundle, their values will be overwritten by
+	 * the Framework.
+	 * <li>The service is added to the Framework service registry and may now
+	 * be used by others.
+	 * <li>A service event of type {@link org.osgi.framework.ServiceEvent#REGISTERED} is
+	 * fired. This event triggers the corresponding {@link ApplicationServiceEvent} to be 
+	 * delivered to the applications that registered the appropriate listener.
+	 * <li>A <code>ServiceRegistration</code> object for this registration is
+	 * returned.
+	 * </ol>
+	 * 
+	 * @param clazzes The class names under which the service can be located.
+	 *        The class names in this array will be stored in the service's
+	 *        properties under the key {@link org.osgi.framework.Constants#OBJECTCLASS}.
+     *        This parameter must not be <code>null</code>.
+	 * @param service The service object or a <code>ServiceFactory</code>
+	 *        object.
+	 * @param properties The properties for this service. The keys in the
+	 *        properties object must all be <code>String</code> objects. See
+	 *        {@link org.osgi.framework.Constants} for a list of standard service property keys.
+	 *        Changes should not be made to this object after calling this
+	 *        method. To update the service's properties the
+	 *        {@link org.osgi.framework.ServiceRegistration#setProperties} method must be called.
+	 *        The set of properties may be <code>null</code> if the service
+	 *        has no properties.
+	 * 
+	 * @return A {@link org.osgi.framework.ServiceRegistration} object for use by the application
+	 *         registering the service to update the service's properties or to
+	 *         unregister the service.
+	 * 
+	 * @throws java.lang.IllegalArgumentException If one of the following is
+	 *         true:
+	 *         <ul>
+	 *         <li><code>service</code> is <code>null</code>.
+	 *         <li><code>service</code> is not a <code>ServiceFactory</code>
+	 *         object and is not an instance of all the named classes in
+	 *         <code>clazzes</code>.
+	 *         <li><code>properties</code> contains case variants of the same
+	 *         key name.
+	 *         </ul>
+	 * @throws NullPointerException if <code>clazzes</code> is <code>null</code>
+     * 
+	 * @throws java.lang.SecurityException If the caller does not have the
+	 *         <code>ServicePermission</code> to register the service for all
+	 *         the named classes and the Java Runtime Environment supports
+	 *         permissions.
+	 * 
+	 * @throws java.lang.IllegalStateException If this ApplicationContext is no
+	 *         longer valid.
+	 * 
+	 * @see org.osgi.framework.BundleContext#registerService(java.lang.String[], java.lang.Object, java.util.Dictionary)
+	 * @see org.osgi.framework.ServiceRegistration
+	 * @see org.osgi.framework.ServiceFactory
+	 */
+    public ServiceRegistration registerService(String[] clazzes,
+            Object service, Dictionary properties);
+
+    /**
+	 * Registers the specified service object with the specified properties
+	 * under the specified class name with the Framework.
+	 * 
+	 * <p>
+	 * This method is otherwise identical to
+	 * {@link #registerService(java.lang.String[], java.lang.Object,
+	 * java.util.Dictionary)} and is provided as a convenience when
+	 * <code>service</code> will only be registered under a single class name.
+	 * Note that even in this case the value of the service's
+	 * {@link Constants#OBJECTCLASS} property will be an array of strings,
+	 * rather than just a single string.
+	 * 
+	 * @param clazz The class name under which the service can be located. It
+     *        must not be <code>null</code>
+	 * @param service The service object or a <code>ServiceFactory</code>
+	 *        object.
+	 * @param properties The properties for this service. 
+	 * 
+	 * @return A <code>ServiceRegistration</code> object for use by the application
+	 *         registering the service to update the service's properties or to
+	 *         unregister the service.
+	 *         
+     * @throws java.lang.IllegalArgumentException If one of the following is
+     *         true:
+     *         <ul>
+     *         <li><code>service</code> is <code>null</code>.
+     *         <li><code>service</code> is not a <code>ServiceFactory</code>
+     *         object and is not an instance of the named class in
+     *         <code>clazz</code>.
+     *         <li><code>properties</code> contains case variants of the same
+     *         key name.
+     *         </ul>
+     * @throws NullPointerException if <code>clazz</code> is <code>null</code>
+     * 
+     * @throws java.lang.SecurityException If the caller does not have the
+     *         <code>ServicePermission</code> to register the service 
+     *         the named class and the Java Runtime Environment supports
+     *         permissions.
+     *
+	 * @throws java.lang.IllegalStateException If this ApplicationContext is no
+	 *         longer valid.
+	 * @see #registerService(java.lang.String[], java.lang.Object,
+	 *      java.util.Dictionary)
+	 */
+    public ServiceRegistration registerService(String clazz, Object service,
+            Dictionary properties);
+}

Added: felix/trunk/deploymentadmin/src/main/java/org/osgi/application/ApplicationServiceEvent.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/osgi/application/ApplicationServiceEvent.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/osgi/application/ApplicationServiceEvent.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/osgi/application/ApplicationServiceEvent.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,83 @@
+/*
+ * $Header: /cvshome/build/org.osgi.application/src/org/osgi/application/ApplicationServiceEvent.java,v 1.6 2006/07/11 13:19:02 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2005, 2006). All Rights Reserved.
+ * 
+ * Licensed 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.osgi.application;
+
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * An event from the Framework describing a service lifecycle change.
+ * <p>
+ * <code>ApplicationServiceEvent</code> objects are delivered to a
+ * <code>ApplicationServiceListener</code> objects when a change occurs in this service's
+ * lifecycle. The delivery of an <code>ApplicationServiceEvent</code> is 
+ * always triggered by a {@link org.osgi.framework.ServiceEvent}.
+ * <code>ApplicationServiceEvent</code> extends the content of <code>ServiceEvent</code>
+ * with the service object the event is referring to as applications has no means to
+ * find the corresponding service object for a {@link org.osgi.framework.ServiceReference}.
+ * A type code is used to identify the event type for future
+ * extendability. The available type codes are defined in {@link org.osgi.framework.ServiceEvent}.
+ * 
+ * <p>
+ * OSGi Alliance reserves the right to extend the set of types.
+ * 
+ * @see org.osgi.framework.ServiceEvent
+ * @see ApplicationServiceListener
+ * 
+ * @version $Revision: 1.6 $
+ */
+public class ApplicationServiceEvent extends ServiceEvent {
+
+	private static final long serialVersionUID = -4762149286971897323L;
+	final Object serviceObject;
+
+	/**
+	 * Creates a new application service event object.
+	 * 
+	 * @param type The event type. Available type codes are defines in 
+	 *        {@link org.osgi.framework.ServiceEvent}
+	 * @param reference A <code>ServiceReference</code> object to the service
+	 *        that had a lifecycle change. This reference will be used as the <code>source</code>
+	 *        in the {@link java.util.EventObject} baseclass, therefore, it must not be
+	 *        null.
+	 * @param serviceObject The service object bound to this application instance. It can
+	 *    be <code>null</code> if this application is not bound to this service yet.
+	 * @throws IllegalArgumentException if the specified <code>reference</code> is null. 
+	 */
+	public ApplicationServiceEvent(int type, ServiceReference reference, Object serviceObject) {
+		super(type, reference);
+		this.serviceObject = serviceObject;
+	}
+	
+	/**
+	 * This method returns the service object of this service bound to the listener
+	 * application instace. A service object becomes bound to the application when it
+	 * first obtains a service object reference to that service by calling the
+	 * <code>ApplicationContext.locateService</code> or <code>locateServices</code>
+	 * methods. If the application is not bound to the service yet, this method returns
+	 * <code>null</code>.
+	 * 
+	 * @return the service object bound to the listener application or <code>null</code>
+	 *   if it isn't bound to this service yet.
+	 */
+	public Object getServiceObject() {
+		return this.serviceObject;
+	}
+
+}

Added: felix/trunk/deploymentadmin/src/main/java/org/osgi/application/ApplicationServiceListener.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/osgi/application/ApplicationServiceListener.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/osgi/application/ApplicationServiceListener.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/osgi/application/ApplicationServiceListener.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,68 @@
+/*
+ * $Header: /cvshome/build/org.osgi.application/src/org/osgi/application/ApplicationServiceListener.java,v 1.6 2006/07/12 21:21:34 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2005, 2006). All Rights Reserved.
+ * 
+ * Licensed 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.osgi.application;
+
+import java.util.EventListener;
+
+import org.osgi.framework.*;
+
+/**
+ * An <code>ApplicationServiceEvent</code> listener. When a 
+ * <code>ServiceEvent</code> is
+ * fired, it is converted to an <code>ApplictionServiceEvent</code>
+ * and it is synchronously delivered to an <code>ApplicationServiceListener</code>.
+ * 
+ * <p>
+ * <code>ApplicationServiceListener</code> is a listener interface that may be
+ * implemented by an application developer.
+ * <p>
+ * An <code>ApplicationServiceListener</code> object is registered with the Framework
+ * using the <code>ApplicationContext.addServiceListener</code> method.
+ * <code>ApplicationServiceListener</code> objects are called with an
+ * <code>ApplicationServiceEvent</code> object when a service is registered, modified, or
+ * is in the process of unregistering.
+ * 
+ * <p>
+ * <code>ApplicationServiceEvent</code> object delivery to 
+ * <code>ApplicationServiceListener</code>
+ * objects is filtered by the filter specified when the listener was registered.
+ * If the Java Runtime Environment supports permissions, then additional
+ * filtering is done. <code>ApplicationServiceEvent</code> objects are only delivered to
+ * the listener if the application which defines the listener object's class has the
+ * appropriate <code>ServicePermission</code> to get the service using at
+ * least one of the named classes the service was registered under, and the application
+ * specified its dependece on the corresponding service in the application metadata.
+ * 
+ * <p>
+ * <code>ApplicationServiceEvent</code> object delivery to <code>ApplicationServiceListener</code>
+ * objects is further filtered according to package sources as defined in
+ * {@link ServiceReference#isAssignableTo(Bundle, String)}.
+ * 
+ * @version $Revision: 1.6 $
+ * @see ApplicationServiceEvent
+ * @see ServicePermission
+ */
+public interface ApplicationServiceListener extends EventListener {
+	/**
+	 * Receives notification that a service has had a lifecycle change.
+	 * 
+	 * @param event The <code>ApplicationServiceEvent</code> object.
+	 */
+	public void serviceChanged(ApplicationServiceEvent event);
+}

Added: felix/trunk/deploymentadmin/src/main/java/org/osgi/application/Framework.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/osgi/application/Framework.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/osgi/application/Framework.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/osgi/application/Framework.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,59 @@
+/*
+ * $Header: /cvshome/build/org.osgi.application/src/org/osgi/application/Framework.java,v 1.9 2006/07/11 13:19:02 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2005, 2006). All Rights Reserved.
+ * 
+ * Licensed 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.osgi.application;
+
+import java.util.Hashtable;
+
+/**
+ * Using this class, OSGi-aware applications can obtain their {@link ApplicationContext}. 
+ *
+ */
+public final class Framework {
+
+    private Framework() { }
+    
+    private static Hashtable appContextHash;
+    
+    /**
+     * This method needs an argument, an object that represents the application instance. 
+     * An application consists of a set of object, however there is a single object, which 
+     * is used by the corresponding application container to manage the lifecycle on the 
+     * application instance. The lifetime of this object equals the lifetime of 
+     * the application instance; therefore, it is suitable to represent the instance. 
+     * <P>
+     * The returned {@link ApplicationContext} object is singleton for the 
+     * specified application instance. Subsequent calls to this method with the same 
+     * application instance must return the same context object
+     * 
+     * @param applicationInstance is the activator object of an application instance
+     * @throws java.lang.NullPointerException If <code>applicationInstance</code>
+     *     is <code>null</code>      
+     * @throws java.lang.IllegalArgumentException if  called with an object that is not 
+     *     the activator object of an application.
+     * @return the {@link ApplicationContext} of the specified application instance.
+     */
+    public static ApplicationContext getApplicationContext(Object applicationInstance) {
+    	  if( applicationInstance == null )
+    		  throw new NullPointerException( "Instance cannot be null!" );
+    	  ApplicationContext appContext = (ApplicationContext)appContextHash.get( applicationInstance );
+    	  if( appContext == null )
+    		  throw new IllegalArgumentException( "ApplicationContext not found!" );
+        return appContext;        
+    }
+}

Added: felix/trunk/deploymentadmin/src/main/java/org/osgi/application/package.html
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/osgi/application/package.html?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/osgi/application/package.html (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/osgi/application/package.html Wed Jan 30 08:46:24 2008
@@ -0,0 +1,10 @@
+<!-- $Header: /cvshome/build/org.osgi.application/src/org/osgi/application/package.html,v 1.2 2006/07/12 21:07:09 hargrave Exp $ -->
+<BODY>
+<p>Foreign Application Package Version 1.0.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.application; version=1.0
+</pre>
+</BODY>

Added: felix/trunk/deploymentadmin/src/main/java/org/osgi/application/packageinfo
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/osgi/application/packageinfo?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/osgi/application/packageinfo (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/osgi/application/packageinfo Wed Jan 30 08:46:24 2008
@@ -0,0 +1 @@
+version 1.0

Added: felix/trunk/deploymentadmin/src/main/java/org/osgi/service/application/ApplicationAdminPermission.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/osgi/service/application/ApplicationAdminPermission.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/osgi/service/application/ApplicationAdminPermission.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/osgi/service/application/ApplicationAdminPermission.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,407 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.application/src/org/osgi/service/application/ApplicationAdminPermission.java,v 1.34 2006/07/12 21:22:11 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2004, 2006). All Rights Reserved.
+ * 
+ * Licensed 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.osgi.service.application;
+
+import java.security.Permission;
+import java.util.*;
+
+import org.osgi.framework.*;
+
+/**
+ * This class implements permissions for manipulating applications and
+ * their instances.
+ * <P>
+ * ApplicationAdminPermission can be targeted to applications that matches the
+ * specified filter.
+ * <P>
+ * ApplicationAdminPermission may be granted for different actions:
+ * <code>lifecycle</code>, <code>schedule</code> and <code>lock</code>.
+ * The permission <code>schedule</code> implies the permission
+ * <code>lifecycle</code>.
+ */
+public class ApplicationAdminPermission extends Permission {
+	private static final long serialVersionUID = 1L;
+  
+	/**
+	 * Allows the lifecycle management of the target applications.
+	 */
+	public static final String LIFECYCLE_ACTION = "lifecycle";
+
+	/**
+	 * Allows scheduling of the target applications. The permission to
+	 * schedule an application implies that the scheduler can also 
+	 * manage the lifecycle of that application i.e. <code>schedule</code>
+	 * implies <code>lifecycle</code>
+	 */
+	public static final String SCHEDULE_ACTION = "schedule";
+
+	/**
+	 * Allows setting/unsetting the locking state of the target applications.
+	 */
+	public static final String LOCK_ACTION = "lock";
+
+	private ApplicationDescriptor	applicationDescriptor;
+
+	/**
+	 * Constructs an ApplicationAdminPermission. The <code>filter</code>
+	 * specifies the target application. The <code>filter</code> is an
+	 * LDAP-style filter, the recognized properties are <code>signer</code>
+	 * and <code>pid</code>. The pattern specified in the <code>signer</code>
+	 * is matched with the Distinguished Name chain used to sign the application. 
+	 * Wildcards in a DN are not matched according to the filter string rules, 
+	 * but according to the rules defined for a DN chain. The attribute 
+	 * <code>pid</code> is matched with the PID of the application according to
+	 * the filter string rules. 
+	 * <p>
+	 * If the <code>filter</code> is <code>null</code> then it matches 
+	 * <code>"*"</code>. If
+	 * <code>actions</code> is <code>"*"</code> then it identifies all the
+	 * possible actions.
+	 * 
+	 * @param filter
+	 *            filter to identify application. The value <code>null</code>
+	 *            is equivalent to <code>"*"</code> and it indicates "all application".
+	 * @param actions
+	 *            comma-separated list of the desired actions granted on the
+	 *            applications or "*" means all the actions. It must not be
+	 *            <code>null</code>. The order of the actions in the list is
+	 *            not significant.
+	 * @throws InvalidSyntaxException 
+	 *            is thrown if the specified <code>filter</code> is not syntactically
+	 *            correct.
+	 * 
+	 * @exception NullPointerException
+	 *                is thrown if the actions parameter is <code>null</code>
+	 * 
+	 * @see ApplicationDescriptor
+	 * @see org.osgi.framework.AdminPermission
+	 */
+	public ApplicationAdminPermission(String filter, String actions) throws InvalidSyntaxException {
+		super(filter == null ? "*" : filter);
+		
+		if( filter == null )
+			filter = "*";
+		
+		if( actions == null )
+			throw new NullPointerException( "Action string cannot be null!" );
+		
+		this.applicationDescriptor = null;
+		this.filter = (filter == null ? "*" : filter);
+		this.actions = actions;
+
+		if( !filter.equals( "*" ) && !filter.equals( "<<SELF>>" ) )
+			FrameworkUtil.createFilter( this.filter ); // check if the filter is valid
+		init();
+	}
+	
+	/**
+	 * This contructor should be used when creating <code>ApplicationAdminPermission</code>
+	 * instance for <code>checkPermission</code> call. 
+	 * @param application the tareget of the operation, it must not be <code>null</code>
+	 * @param actions the required operation. it must not be <code>null</code>
+	 * @throws NullPointerException if any of the arguments is null. 
+	 */
+	public ApplicationAdminPermission(ApplicationDescriptor application, String actions) {
+		super(application.getApplicationId());
+				
+		if( application == null || actions == null )
+			throw new NullPointerException( "ApplicationDescriptor and action string cannot be null!" );
+		
+		this.filter = application.getApplicationId();
+		this.applicationDescriptor = application;
+		this.actions = actions;
+		
+		init();
+	}
+	
+	/**
+	 * This method can be used in the {@link java.security.ProtectionDomain}
+	 * implementation in the <code>implies</code> method to insert the
+	 * application ID of the current application into the permission being
+	 * checked. This enables the evaluation of the 
+	 * <code>&lt;&lt;SELF&gt;&gt;</code> pseudo targets.
+	 * @param applicationId the ID of the current application.
+	 * @return the permission updated with the ID of the current application
+	 */
+	public ApplicationAdminPermission setCurrentApplicationId(String applicationId) {
+		ApplicationAdminPermission newPerm = null;
+		
+		if( this.applicationDescriptor == null ) {
+			try {
+				newPerm = new ApplicationAdminPermission( this.filter, this.actions );
+			}catch( InvalidSyntaxException e ) {
+				throw new RuntimeException( "Internal error" ); /* this can never happen */
+			}
+		}
+		else	
+		    newPerm = new ApplicationAdminPermission( this.applicationDescriptor, this.actions );
+		
+		newPerm.applicationID = applicationId;
+		
+		return newPerm;
+	}
+
+	/**
+	 * Checks if the specified <code>permission</code> is implied by this permission.
+	 * The method returns true under the following conditions:
+	 * <UL>
+	 * <LI> This permission was created by specifying a filter (see {@link #ApplicationAdminPermission(String, String)})
+	 * <LI> The implied <code>otherPermission</code> was created for a particular {@link ApplicationDescriptor}
+	 *      (see {@link #ApplicationAdminPermission(ApplicationDescriptor, String)})
+	 * <LI> The <code>filter</code> of this permission mathes the <code>ApplicationDescriptor</code> specified
+	 *      in the <code>otherPermission</code>. If the filter in this permission is the 
+	 *      <code>&lt;&lt;SELF&gt;&gt;</code> pseudo target, then the currentApplicationId set in the 
+	 *      <code>otherPermission</code> is compared to the application Id of the target 
+	 *      <code>ApplicationDescriptor</code>.
+	 * <LI> The list of permitted actions in this permission contains all actions required in the 
+	 *      <code>otherPermission</code>  
+	 * </UL> 
+	 * Otherwise the method returns false.
+	 * @param otherPermission the implied permission
+	 * @return true if this permission implies the <code>otherPermission</code>, false otherwise.
+	 */
+  public boolean implies(Permission otherPermission) {
+  	  if( otherPermission == null )
+  	  	return false;
+  	  	
+      if(!(otherPermission instanceof ApplicationAdminPermission))
+          return false;
+
+      ApplicationAdminPermission other = (ApplicationAdminPermission) otherPermission;
+
+      if( !filter.equals("*") ) {
+       	if( other.applicationDescriptor == null )
+       		return false;
+       	
+      	if( filter.equals( "<<SELF>>") ) {
+            if( other.applicationID == null )
+          		return false; /* it cannot be, this might be a bug */
+            
+      		if( !other.applicationID.equals( other.applicationDescriptor.getApplicationId() ) )
+      			return false;
+      	}
+      	else {
+      		Hashtable props = new Hashtable();
+      		props.put( "pid", other.applicationDescriptor.getApplicationId() );
+      		props.put( "signer", new SignerWrapper( other.applicationDescriptor ) );
+      		      		
+      		Filter flt = getFilter();
+      		if( flt == null )
+      			return false;
+      		
+      		if( !flt.match( props ) )
+      			return false;
+      	}
+      }
+      
+      if( !actionsVector.containsAll( other.actionsVector ) )
+      	return false;
+      
+      return true;
+  }
+
+  public boolean equals(Object with) {
+  	if( with == null || !(with instanceof ApplicationAdminPermission) )
+  		return false;
+  	
+  	ApplicationAdminPermission other = (ApplicationAdminPermission)with;  	
+  	
+  	// Compare actions:
+  	if( other.actionsVector.size() != actionsVector.size() )
+  		return false;
+  	
+  	for( int i=0; i != actionsVector.size(); i++ )
+  		if( !other.actionsVector.contains( actionsVector.get( i ) ) )
+  			return false;
+  	
+  	
+  	return equal(this.filter, other.filter ) && equal(this.applicationDescriptor, other.applicationDescriptor)
+  			&& equal(this.applicationID, other.applicationID);
+  }
+  
+  /**
+   * Compares parameters for equality. If both object are null, they are considered
+   * equal.
+   * @param a object to compare
+   * @param b other object to compare
+   * @return true if both objects are equal or both are null
+   */
+  private static boolean equal(Object a, Object b) {
+	  // This equation is true if both references are null or both point
+	  // to the same object. In both cases they are considered as equal.
+	  if( a == b ) {
+		  return true;
+	  }
+	  
+	  return a.equals(b);
+  }
+
+  public int hashCode() {
+	  int hc = 0;
+	  for( int i=0; i != actionsVector.size(); i++ )
+		  hc ^= ((String)actionsVector.get( i )).hashCode();
+	  hc ^= (null == this.filter )? 0 : this.filter.hashCode();
+	  hc ^= (null == this.applicationDescriptor) ? 0 : this.applicationDescriptor.hashCode();
+	  hc ^= (null == this.applicationID) ? 0 : this.applicationID.hashCode();
+	  return hc;
+  }
+
+  /**
+   * Returns the actions of this permission.
+   * @return the actions specified when this permission was created
+   */
+  public String getActions() {
+  	return actions;
+  }
+
+  private String applicationID;
+
+  private static final Vector ACTIONS = new Vector();
+  private              Vector actionsVector;
+  private final        String filter;
+  private final        String actions;
+  private              Filter appliedFilter = null; 
+  
+  static {
+      ACTIONS.add(LIFECYCLE_ACTION);
+      ACTIONS.add(SCHEDULE_ACTION);
+      ACTIONS.add(LOCK_ACTION);
+  }
+
+  private static Vector actionsVector(String actions) {
+      Vector v = new Vector();
+      StringTokenizer t = new StringTokenizer(actions.toUpperCase(), ",");
+      while (t.hasMoreTokens()) {
+          String action = t.nextToken().trim();
+          v.add(action.toLowerCase());
+      }
+      
+      if( v.contains( SCHEDULE_ACTION ) && !v.contains( LIFECYCLE_ACTION ) )
+    	  v.add( LIFECYCLE_ACTION );
+      
+      return v;
+  }
+  
+
+  private static class SignerWrapper extends Object {
+  	private String pattern;
+  	private ApplicationDescriptor appDesc;
+  	
+  	public SignerWrapper(String pattern) {
+  		this.pattern = pattern;    			
+  	}
+  	
+  	SignerWrapper(ApplicationDescriptor appDesc) {
+  		this.appDesc = appDesc;
+  	}
+  	
+  	public boolean equals(Object o) {
+  		if (!(o instanceof SignerWrapper))
+  			return false;
+  		SignerWrapper other = (SignerWrapper) o;
+  		ApplicationDescriptor matchAppDesc = (ApplicationDescriptor) (appDesc != null ? appDesc : other.appDesc);
+  		String matchPattern = appDesc != null ? other.pattern : pattern;
+  		return matchAppDesc.matchDNChain(matchPattern);
+  	}
+  }
+  
+  private void init() {
+		actionsVector = actionsVector( actions );
+
+		if ( actions.equals("*") )
+			actionsVector = actionsVector( LIFECYCLE_ACTION + "," + SCHEDULE_ACTION + "," + LOCK_ACTION );
+		else if (!ACTIONS.containsAll(actionsVector))
+      throw new IllegalArgumentException("Illegal action!");
+		
+		applicationID = null;
+  }
+  
+  private Filter getFilter() {
+  	String transformedFilter = filter;
+  	
+  	if (appliedFilter == null) {
+  		try {
+  			int pos = filter.indexOf("signer"); //$NON-NLS-1$
+  			if (pos != -1){ 
+  			
+  				//there may be a signer attribute 
+    			StringBuffer filterBuf = new StringBuffer(filter);
+    			int numAsteriskFound = 0; //use as offset to replace in buffer
+    			
+    			int walkbackPos; //temp pos
+
+    			//find occurences of (signer= and escape out *'s
+    			while (pos != -1) {
+
+    				//walk back and look for '(' to see if this is an attr
+    				walkbackPos = pos-1; 
+    				
+    				//consume whitespace
+    				while(walkbackPos >= 0 && Character.isWhitespace(filter.charAt(walkbackPos))) {
+    					walkbackPos--;
+    				}
+    				if (walkbackPos <0) {
+    					//filter is invalid - FilterImpl will throw error
+    					break;
+    				}
+    				
+    				//check to see if we have unescaped '('
+    				if (filter.charAt(walkbackPos) != '(' || (walkbackPos > 0 && filter.charAt(walkbackPos-1) == '\\')) {
+    					//'(' was escaped or not there
+    					pos = filter.indexOf("signer",pos+6); //$NON-NLS-1$
+    					continue;
+    				}     				
+    				pos+=6; //skip over 'signer'
+
+    				//found signer - consume whitespace before '='
+    				while (Character.isWhitespace(filter.charAt(pos))) {
+    					pos++;
+    				}
+
+    				//look for '='
+    				if (filter.charAt(pos) != '=') {
+    					//attr was signerx - keep looking
+    					pos = filter.indexOf("signer",pos); //$NON-NLS-1$
+    					continue;
+    				}
+    				pos++; //skip over '='
+    				
+    				//found signer value - escape '*'s
+    				while (!(filter.charAt(pos) == ')' && filter.charAt(pos-1) != '\\')) {
+    					if (filter.charAt(pos) == '*') {
+    						filterBuf.insert(pos+numAsteriskFound,'\\');
+    						numAsteriskFound++;
+    					}
+    					pos++;
+    				}
+
+    				//end of signer value - look for more?
+    				pos = filter.indexOf("signer",pos); //$NON-NLS-1$
+    			} //end while (pos != -1)
+    			transformedFilter = filterBuf.toString();
+  			} //end if (pos != -1)
+
+  			appliedFilter = FrameworkUtil.createFilter( transformedFilter );
+		} catch (InvalidSyntaxException e) {
+			//we will return null
+		}
+  	}     		
+  	return appliedFilter;
+  }
+}

Added: felix/trunk/deploymentadmin/src/main/java/org/osgi/service/application/ApplicationDescriptor.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/osgi/service/application/ApplicationDescriptor.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/osgi/service/application/ApplicationDescriptor.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/osgi/service/application/ApplicationDescriptor.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,714 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.application/src/org/osgi/service/application/ApplicationDescriptor.java,v 1.61 2006/07/10 12:02:31 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2004, 2006). All Rights Reserved.
+ * 
+ * Licensed 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.osgi.service.application;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.security.*;
+import java.util.Map;
+
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+
+/**
+ * An OSGi service that represents an installed application and stores
+ * information about it. The application descriptor can be used for instance
+ * creation.
+ */
+
+public abstract class ApplicationDescriptor {
+	/*
+	 * NOTE: An implementor may also choose to replace this class in
+	 * their distribution with a class that directly interfaces with the
+	 * org.osgi.service.application implementation. This replacement class MUST NOT alter the
+	 * public/protected signature of this class.
+	 */
+
+	/**
+	 * The property key for the localized name of the application.
+	 */
+	public static final String APPLICATION_NAME = "application.name";
+
+	/**
+	 * The property key for the localized icon of the application.
+	 */
+	public static final String APPLICATION_ICON = "application.icon";
+
+	/**
+	 * The property key for the unique identifier (PID) of the application.
+	 */
+	public static final String APPLICATION_PID = Constants.SERVICE_PID;
+
+	/**
+	 * The property key for the version of the application.
+	 */
+	public static final String APPLICATION_VERSION = "application.version";
+
+	/**
+	 * The property key for the name of the application vendor.
+	 */
+	public static final String APPLICATION_VENDOR = Constants.SERVICE_VENDOR;
+
+
+	/**
+	 * The property key for the visibility property of the application.
+	 */
+	public static final String APPLICATION_VISIBLE = "application.visible";
+
+	/**
+	 * The property key for the launchable property of the application.
+	 */
+	public static final String APPLICATION_LAUNCHABLE = "application.launchable";
+
+	/**
+	 * The property key for the locked property of the application.
+	 */
+	public static final String APPLICATION_LOCKED = "application.locked";
+
+	/**
+	 * The property key for the localized description of the application.
+	 */
+	public static final String APPLICATION_DESCRIPTION = "application.description";
+
+	/**
+	 * The property key for the localized documentation of the application.
+	 */
+	public static final String APPLICATION_DOCUMENTATION = "application.documentation";
+
+	/**
+	 * The property key for the localized copyright notice of the application.
+	 */
+	public static final String APPLICATION_COPYRIGHT = "application.copyright";
+
+	/**
+	 * The property key for the localized license of the application.
+	 */
+	public static final String APPLICATION_LICENSE = "application.license";
+
+	/**
+	 * The property key for the application container of the application.
+	 */
+	public static final String APPLICATION_CONTAINER = "application.container";
+
+	/**
+	 * The property key for the location of the application.
+	 */
+	public static final String APPLICATION_LOCATION = "application.location";
+
+	
+	private final String	pid;
+
+
+	/**
+	 * Constructs the <code>ApplicationDescriptor</code>.
+	 *
+	 * @param applicationId
+	 *            The identifier of the application. Its value is also available
+	 *            as the <code>service.pid</code> service property of this 
+	 *            <code>ApplicationDescriptor</code> service. This parameter must not
+	 *            be <code>null</code>.
+	 * @throws NullPointerException if the specified <code>applicationId</code> is null.
+	 */
+	protected  ApplicationDescriptor(String applicationId) {
+		if(null == applicationId ) {
+			throw new NullPointerException("Application ID must not be null!");
+		}
+		
+		this.pid = applicationId;
+		try {
+			delegate = new Delegate();
+			delegate.setApplicationDescriptor( this, applicationId );
+		}
+		catch (Exception e) {
+			// Too bad ...
+			e.printStackTrace();
+			System.err
+					.println("No implementation available for ApplicationDescriptor, property is: "
+							+ Delegate.cName);
+		}
+	}
+
+	/**
+	 * Returns the identifier of the represented application.
+	 * 
+	 * @return the identifier of the represented application
+	 */
+	public final String getApplicationId() {
+		return pid;
+	}
+
+	/**
+	 * This method verifies whether the specified <code>pattern</code>
+	 * matches the Distinguished Names of any of the certificate chains
+	 * used to authenticate this application.
+	 * <P>
+	 * The <code>pattern</code> must adhere to the 
+	 * syntax defined in {@link org.osgi.service.application.ApplicationAdminPermission}
+	 * for signer attributes. 
+	 * <p>
+	 * This method is used by {@link ApplicationAdminPermission#implies(java.security.Permission)} method
+	 * to match target <code>ApplicationDescriptor</code> and filter. 
+	 * 
+	 * @param pattern a pattern for a chain of Distinguished Names. It must not be null.
+	 * @return <code>true</code> if the specified pattern matches at least
+	 *   one of the certificate chains used to authenticate this application 
+	 * @throws NullPointerException if the specified <code>pattern</code> is null.
+     * @throws IllegalStateException if the application descriptor was
+     *   unregistered
+	 */	
+	public abstract boolean matchDNChain( String pattern );
+	
+	/**
+	 * Returns the properties of the application descriptor as key-value pairs.
+	 * The return value contains the locale aware and unaware properties as
+	 * well. The returned <code>Map</code> will include the service
+	 * properties of this <code>ApplicationDescriptor</code> as well.
+	 * <p>
+	 * This method will call the <code>getPropertiesSpecific</code> method
+	 * to enable the container implementation to insert application model and/or
+	 * container implementation specific properties.
+	 * <P>
+	 * The returned {@link java.util.Map} will contain the standard OSGi service 
+	 * properties as well
+	 * (e.g. service.id, service.vendor etc.) and specialized application
+	 * descriptors may offer further service properties. The returned Map contains
+	 * a snapshot of the properties. It will not reflect further changes in the
+	 * property values nor will the update of the Map change the corresponding
+	 * service property.
+	 *   
+	 * @param locale
+	 *            the locale string, it may be null, the value null means the
+	 *            default locale. If the provided locale is the empty String 
+	 *            (<code>""</code>)then raw (non-localized) values are returned.
+	 * 
+	 * @return copy of the service properties of this application descriptor service,
+	 *         according to the specified locale. If locale is null then the
+	 *         default locale's properties will be returned. (Since service
+	 *         properties are always exist it cannot return null.)
+	 * 
+	 * @throws IllegalStateException
+	 *             if the application descriptor is unregistered
+	 */
+	public final Map getProperties(String locale) {
+		Map props = getPropertiesSpecific( locale );
+		
+		/* currently the ApplicationDescriptor manages the load/save of locking */
+		boolean isLocked = delegate.isLocked(); // the real locking state
+		Boolean containerLocked = (Boolean)props.remove( APPLICATION_LOCKED );
+		if( containerLocked != null && containerLocked.booleanValue() != isLocked ) {
+			try {
+			  if( isLocked )      /* if the container's information is not correct */
+				  lockSpecific();   /* about the locking state (after loading the lock states) */
+			  else
+				  unlockSpecific();
+			}catch( Exception e ) {}
+		}
+		/* replace the container's lock with the application model's lock, that's the correct */
+		props.put( APPLICATION_LOCKED, new Boolean( isLocked ) ); 		
+		return props;
+	}
+	
+	/**
+	 * Container implementations can provide application model specific
+	 * and/or container implementation specific properties via this 
+	 * method. 
+	 * 
+	 * Localizable properties must be returned localized if the provided
+	 * <code>locale</code> argument is not the empty String. The value
+	 * <code>null</code> indicates to use the default locale, for other
+	 * values the specified locale should be used.
+	 *  
+	 * The returned {@link java.util.Map} must contain the standard OSGi service 
+	 * properties as well
+	 * (e.g. service.id, service.vendor etc.) and specialized application
+	 * descriptors may offer further service properties. 
+	 * The returned <code>Map</code>
+	 * contains a snapshot of the properties. It will not reflect further changes in the
+	 * property values nor will the update of the Map change the corresponding
+	 * service property.
+
+	 * @param locale the locale to be used for localizing the properties.
+	 * If <code>null</code> the default locale should be used. If it is
+	 * the empty String (<code>""</code>) then raw (non-localized) values
+	 * should be returned.
+	 * 
+	 * @return the application model specific and/or container implementation
+	 * specific properties of this application descriptor.
+	 *  
+	 * @throws IllegalStateException
+	 *             if the application descriptor is unregistered
+	 */
+	protected abstract Map getPropertiesSpecific(String locale);
+
+	/**
+	 * Launches a new instance of an application. The <code>args</code> parameter specifies
+	 * the startup parameters for the instance to be launched, it may be null.
+	 * <p>
+	 * The following steps are made:
+	 * <UL>
+	 * <LI>Check for the appropriate permission.
+	 * <LI>Check the locking state of the application. If locked then return
+	 * null otherwise continue.
+	 * <LI>Calls the <code>launchSpecific()</code> method to create and start an application
+	 * instance.
+	 * <LI>Returns the <code>ApplicationHandle</code> returned by the 
+	 * launchSpecific()
+	 * </UL>
+	 * The caller has to have ApplicationAdminPermission(applicationPID,
+	 * "launch") in order to be able to perform this operation.
+	 * <P>
+	 * The <code>Map</code> argument of the launch method contains startup 
+	 * arguments for the
+	 * application. The keys used in the Map must be non-null, non-empty <code>String<code>
+	 * objects. They can be standard or application
+	 * specific. OSGi defines the <code>org.osgi.triggeringevent</code>
+	 * key to be used to
+	 * pass the triggering event to a scheduled application, however
+	 * in the future it is possible that other well-known keys will be defined.
+	 * To avoid unwanted clashes of keys, the following rules should be applied:
+	 * <ul>
+	 *   <li>The keys starting with the dash (-) character are application
+	 *       specific, no well-known meaning should be associated with them.</li>
+	 *   <li>Well-known keys should follow the reverse domain name based naming.
+	 *       In particular, the keys standardized in OSGi should start with
+	 *       <code>org.osgi.</code>.</li>
+	 * </ul>
+	 * <P>
+	 * The method is synchonous, it return only when the application instance was
+	 * successfully started or the attempt to start it failed.
+	 * <P>
+	 * This method never returns <code>null</code>. If launching an application fails,
+	 * the appropriate exception is thrown.
+	 * 
+	 * @param arguments
+	 *            Arguments for the newly launched application, may be null
+	 * 
+	 * @return the registered ApplicationHandle, which represents the newly 
+	 *         launched application instance. Never returns <code>null</code>.
+	 * 
+	 * @throws SecurityException
+	 *             if the caller doesn't have "lifecycle"
+	 *             ApplicationAdminPermission for the application.
+	 * @throws ApplicationException
+	 *             if starting the application failed
+	 * @throws IllegalStateException
+	 *             if the application descriptor is unregistered
+	 * @throws IllegalArgumentException 
+	 *             if the specified <code>Map</code> contains invalid keys
+	 *             (null objects, empty <code>String</code> or a key that is not
+	 *              <code>String</code>)
+	 */
+	public final ApplicationHandle launch(Map arguments)
+			throws ApplicationException {
+		try {
+			delegate.launch(arguments);
+		}catch( SecurityException se ) {
+			isLaunchableSpecific(); /* check whether the bundle was uninstalled */
+			                        /* if yes, throws IllegalStateException */
+			throw se;               /* otherwise throw the catched SecurityException */
+		}
+		if( !isLaunchableSpecific() )
+			throw new ApplicationException(ApplicationException.APPLICATION_NOT_LAUNCHABLE,
+					 "Cannot launch the application!");
+		try {
+			return launchSpecific(arguments);
+		} catch(IllegalStateException ise) {
+			throw ise;
+		} catch(SecurityException se) {
+			throw se;
+		} catch( ApplicationException ae) {
+			throw ae;
+		} catch(Exception t) {
+			throw new ApplicationException(ApplicationException.APPLICATION_INTERNAL_ERROR, t);
+		}
+	}
+
+	/**
+	 * Called by launch() to create and start a new instance in an application
+	 * model specific way. It also creates and registeres the application handle
+	 * to represent the newly created and started instance and registeres it.
+	 * The method is synchonous, it return only when the application instance was
+	 * successfully started or the attempt to start it failed.
+	 * <P>
+	 * This method must not return <code>null</code>. If launching the application
+	 * failed, and exception must be thrown.
+	 * 
+	 * @param arguments
+	 *            the startup parameters of the new application instance, may be
+	 *            null
+	 * 
+	 * @return the registered application model
+	 *         specific application handle for the newly created and started
+	 *         instance.
+	 * 
+	 * @throws IllegalStateException
+	 *             if the application descriptor is unregistered
+	 * @throws Exception
+	 *             if any problem occures.
+	 */
+	protected abstract ApplicationHandle launchSpecific(Map arguments)
+			throws Exception;
+	
+	/**
+	 * This method is called by launch() to verify that according to the
+	 * container, the application is launchable.
+	 * 
+	 * @return true, if the application is launchable according to the 
+	 *  container, false otherwise.
+	 *  
+	 * @throws IllegalStateException
+	 *             if the application descriptor is unregistered
+	 */
+	protected abstract boolean isLaunchableSpecific();
+
+	/**
+	 * Schedules the application at a specified event. Schedule information
+	 * should not get lost even if the framework or the device restarts so it
+	 * should be stored in a persistent storage. The method registers a
+	 * {@link ScheduledApplication} service in Service Registry, representing
+	 * the created schedule.
+	 * <p>
+	 * The <code>Map</code> argument of the  method contains startup 
+	 * arguments for the application. The keys used in the Map must be non-null, 
+	 * non-empty <code>String<code> objects.
+     * <p>
+     * The created schedules have a unique identifier within the scope of this
+     * <code>ApplicationDescriptor</code>. This identifier can be specified
+     * in the <code>scheduleId</code> argument. If this argument is <code>null</code>,
+     * the identifier is automatically generated.
+     * 
+	 * @param scheduleId 
+	 *             the identifier of the created schedule. It can be <code>null</code>,
+     *             in this case the identifier is automatically generated.
+	 * @param arguments
+	 *            the startup arguments for the scheduled application, may be
+	 *            null
+	 * @param topic
+	 *            specifies the topic of the triggering event, it may contain a
+	 *            trailing asterisk as wildcard, the empty string is treated as
+	 *            "*", must not be null
+	 * @param eventFilter
+	 *            specifies and LDAP filter to filter on the properties of the
+	 *            triggering event, may be null
+	 * @param recurring
+	 *            if the recurring parameter is false then the application will
+	 *            be launched only once, when the event firstly occurs. If the
+	 *            parameter is true then scheduling will take place for every
+	 *            event occurrence; i.e. it is a recurring schedule
+	 * 
+	 * @return the registered scheduled application service
+	 * 
+	 * @throws NullPointerException
+	 *             if the topic is <code>null</code>
+	 * @throws InvalidSyntaxException 
+	 * 			   if the specified <code>eventFilter</code> is not syntactically correct
+	 * @throws ApplicationException
+     *              if the schedule couldn't be created. The possible error
+     *              codes are 
+     *              <ul>
+     *               <li> {@link ApplicationException#APPLICATION_DUPLICATE_SCHEDULE_ID}
+     *                 if the specified <code>scheduleId</code> is already used
+     *                 for this <code>ApplicationDescriptor</code>
+     *               <li> {@link ApplicationException#APPLICATION_SCHEDULING_FAILED}
+     *                 if the scheduling failed due to some internal reason
+     *                 (e.g. persistent storage error).
+     *              </ul>
+	 * @throws SecurityException
+	 *             if the caller doesn't have "schedule"
+	 *             ApplicationAdminPermission for the application.
+	 * @throws IllegalStateException
+	 *             if the application descriptor is unregistered
+	 * @throws IllegalArgumentException
+	 *             if the specified <code>Map</code> contains invalid keys
+	 *             (null objects, empty <code>String</code> or a key that is not
+	 *              <code>String</code>)
+	 */
+	public final ScheduledApplication schedule(String scheduleId, Map arguments, String topic,
+			String eventFilter, boolean recurring) throws InvalidSyntaxException, 
+            ApplicationException {
+		isLaunchableSpecific(); // checks if the ApplicationDescriptor was already unregistered
+		try {
+			return delegate.schedule(scheduleId, arguments, topic, eventFilter, recurring);
+		}catch( SecurityException se ) {
+			isLaunchableSpecific(); /* check whether the bundle was uninstalled */
+			                        /* if yes, throws IllegalStateException */
+			throw se;               /* otherwise throw the catched SecurityException */
+		}
+	}
+
+	/**
+	 * Sets the lock state of the application. If an application is locked then
+	 * launching a new instance is not possible. It does not affect the already
+	 * launched instances.
+	 * 
+	 * @throws SecurityException
+	 *             if the caller doesn't have "lock" ApplicationAdminPermission
+	 *             for the application.
+	 * @throws IllegalStateException
+	 *             if the application descriptor is unregistered
+	 */
+	public final void lock() {
+		try {
+			delegate.lock();
+		}catch( SecurityException se ) {
+			isLaunchableSpecific(); /* check whether the bundle was uninstalled */
+			                        /* if yes, throws IllegalStateException */
+			throw se;               /* otherwise throw the catched SecurityException */
+		}
+		lockSpecific();
+	}
+	
+	/**
+	 * This method is used to notify the container implementation that the
+	 * corresponding application has been locked and it should update the
+	 * <code>application.locked</code> service property accordingly.
+     * @throws IllegalStateException
+     *             if the application descriptor is unregistered
+	 */
+	protected abstract void lockSpecific();
+
+	/**
+	 * Unsets the lock state of the application.
+	 * 
+	 * @throws SecurityException
+	 *             if the caller doesn't have "lock" ApplicationAdminPermission
+	 *             for the application.
+	 * @throws IllegalStateException
+	 *             if the application descriptor is unregistered
+	 */
+	public final void unlock() {
+		try {
+			delegate.unlock();
+		}catch( SecurityException se ) {
+			isLaunchableSpecific(); /* check whether the bundle was uninstalled */
+			                        /* if yes, throws IllegalStateException */
+			throw se;               /* otherwise throw the catched SecurityException */
+		}
+		unlockSpecific();
+	}
+	
+	/**
+	 * This method is used to notify the container implementation that the
+	 * corresponding application has been unlocked and it should update the
+	 * <code>application.locked</code> service property accordingly.
+
+	 * @throws IllegalStateException
+	 *             if the application descriptor is unregistered
+	 */
+	protected abstract void unlockSpecific();
+
+	Delegate	delegate;
+	/**
+	 * This class will load the class named
+	 * by the org.osgi.vendor.application.ApplicationDescriptor and delegate
+	 * method calls to an instance of the class.
+	 */
+	static class Delegate {
+		static String cName;
+		static Class implementation;
+		static Method setApplicationDescriptor;
+		static Method isLocked;
+		static Method lock;
+		static Method unlock;
+		static Method schedule;
+		static Method launch;
+		
+		static {
+			AccessController.doPrivileged(new PrivilegedAction() {
+				public Object run() {			
+					cName = System.getProperty("org.osgi.vendor.application.ApplicationDescriptor");
+					if (cName == null) {
+						throw new NoClassDefFoundError("org.osgi.vendor.application.ApplicationDescriptor property must be set"); 
+					}
+					
+					try {
+						implementation = Class.forName(cName);
+					}
+					catch (ClassNotFoundException e) {
+						throw new NoClassDefFoundError(e.toString());
+					}
+					
+					try {
+						setApplicationDescriptor = implementation.getMethod("setApplicationDescriptor",
+								new Class[] {ApplicationDescriptor.class, String.class});
+						isLocked = implementation.getMethod("isLocked",
+								new Class[] {});
+						lock = implementation.getMethod("lock",
+								new Class[] {});
+						unlock = implementation.getMethod("unlock",
+								new Class[] {});
+						schedule = implementation.getMethod("schedule",
+								new Class[] {String.class, Map.class, String.class, String.class,
+								boolean.class});
+						launch = implementation.getMethod("launch",
+								new Class[] {Map.class});
+					}
+					catch (NoSuchMethodException e) {
+						throw new NoSuchMethodError(e.toString());
+					}
+					
+					return null;
+				}
+			});
+		}
+
+		Object target; 
+		
+		Delegate() throws Exception {
+			target = AccessController.doPrivileged(new PrivilegedExceptionAction() {
+				public Object run() throws Exception {			
+					return implementation.newInstance();
+				}
+			});
+		}
+
+		void setApplicationDescriptor(ApplicationDescriptor d, String pid ) {
+			try {
+				try {
+					setApplicationDescriptor.invoke(target, new Object[] {d, pid});
+				}
+				catch (InvocationTargetException e) {
+					throw e.getTargetException();
+				}
+			}
+			catch (Error e) {
+				throw e;
+			}
+			catch (RuntimeException e) {
+				throw e;
+			}
+			catch (Throwable e) {
+				throw new RuntimeException(e.toString());
+			}
+		}
+
+		boolean isLocked() {
+			try {
+				try {
+					return ((Boolean)isLocked.invoke(target, new Object[] {})).booleanValue();
+				}
+				catch (InvocationTargetException e) {
+					throw e.getTargetException();
+				}
+			}
+			catch (Error e) {
+				throw e;
+			}
+			catch (RuntimeException e) {
+				throw e;
+			}
+			catch (Throwable e) {
+				throw new RuntimeException(e.toString());
+			}
+		}
+
+		void lock() {
+			try {
+				try {
+					lock.invoke(target, new Object[] {});
+				}
+				catch (InvocationTargetException e) {
+					throw e.getTargetException();
+				}
+			}
+			catch (Error e) {
+				throw e;
+			}
+			catch (RuntimeException e) {
+				throw e;
+			}
+			catch (Throwable e) {
+				throw new RuntimeException(e.toString());
+			}
+		}
+
+		void unlock() {
+			try {
+				try {
+					unlock.invoke(target, new Object[] {});
+				}
+				catch (InvocationTargetException e) {
+					throw e.getTargetException();
+				}
+			}
+			catch (Error e) {
+				throw e;
+			}
+			catch (RuntimeException e) {
+				throw e;
+			}
+			catch (Throwable e) {
+				throw new RuntimeException(e.toString());
+			}
+		}
+
+		ScheduledApplication schedule(String scheduleId, Map args, String topic, String filter,
+				boolean recurs) throws InvalidSyntaxException, ApplicationException {
+			try {
+				try {
+					return (ScheduledApplication)schedule.invoke(target, new Object[] {scheduleId, args, topic, filter,
+							new Boolean(recurs)});
+				}
+				catch (InvocationTargetException e) {
+					throw e.getTargetException();
+				}
+			}
+			catch (InvalidSyntaxException e) {
+				throw e;
+			}
+			catch (ApplicationException e) {
+				throw e;
+			}
+			catch (Error e) {
+				throw e;
+			}
+			catch (RuntimeException e) {
+				throw e;
+			}
+			catch (Throwable e) {
+				throw new RuntimeException(e.toString());
+			}
+		}
+
+		void launch(Map arguments) throws ApplicationException {
+			try {
+				try {
+					launch.invoke(target, new Object[] {arguments});
+				}
+				catch (InvocationTargetException e) {
+					throw e.getTargetException();
+				}
+			}
+			catch (ApplicationException e) {
+				throw e;
+			}
+			catch (Error e) {
+				throw e;
+			}
+			catch (RuntimeException e) {
+				throw e;
+			}
+			catch (Throwable e) {
+				throw new RuntimeException(e.toString());
+			}
+		}
+	}
+
+
+}
\ No newline at end of file

Added: felix/trunk/deploymentadmin/src/main/java/org/osgi/service/application/ApplicationException.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/osgi/service/application/ApplicationException.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/osgi/service/application/ApplicationException.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/osgi/service/application/ApplicationException.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,136 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.application/src/org/osgi/service/application/ApplicationException.java,v 1.10 2006/07/10 11:49:12 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2005, 2006). All Rights Reserved.
+ * 
+ * Licensed 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.osgi.service.application;
+
+/**
+ * This exception is used to indicate problems related to application 
+ * lifecycle management.
+ * 
+ * <code>ApplicationException</code> object is created by the Application Admin to denote
+ * an exception condition in the lifecycle of an application.
+ * <code>ApplicationException</code>s should not be created by developers.
+ * <br/>
+ * <code>ApplicationException</code>s are associated with an error code. This code
+ * describes the type of problem reported in this exception. The possible codes are:
+ * <ul>
+ * <li> {@link #APPLICATION_LOCKED} - The application couldn't be launched because it is locked.</li>
+ * <li> {@link #APPLICATION_NOT_LAUNCHABLE} - The application is not in launchable state.</li>
+ * <li> {@link #APPLICATION_INTERNAL_ERROR} - An exception was thrown by the application or its
+ *       container during launch.</li>
+ * <li> {@link #APPLICATION_SCHEDULING_FAILED} - The scheduling of an application
+ *       failed.
+ * </ul>
+ * 
+ */
+public class ApplicationException extends Exception {
+	private static final long serialVersionUID = -7173190453622508207L;
+	private final Throwable cause;
+	private final int errorCode;
+	
+	/**
+	 * The application couldn't be launched because it is locked.
+	 */
+	public static final int APPLICATION_LOCKED	= 0x01;
+	
+	/**
+	 * The application is not in launchable state, it's 
+	 * {@link ApplicationDescriptor#APPLICATION_LAUNCHABLE}
+	 * attribute is false.
+	 */
+	public static final int APPLICATION_NOT_LAUNCHABLE = 0x02;
+	
+	/**
+	 * An exception was thrown by the application or the corresponding
+	 * container during launch. The exception is available in {@link #getCause()}.
+	 */
+	public static final int APPLICATION_INTERNAL_ERROR = 0x03;
+    
+    /**
+     * The application schedule could not be created due to some internal error
+     * (for example, the schedule information couldn't be saved).
+     */
+    public static final int APPLICATION_SCHEDULING_FAILED = 0x04;
+    
+    /**
+     * The application scheduling failed because the specified identifier
+     * is already in use.
+     */
+    public static final int APPLICATION_DUPLICATE_SCHEDULE_ID = 0x05;
+
+	/**
+	 * Creates an <code>ApplicationException</code> with the specified error code.
+	 * @param errorCode The code of the error 
+	 */
+	public ApplicationException(int errorCode) {
+		this(errorCode,(Throwable) null);
+	}
+	
+	/**
+	 * Creates a <code>ApplicationException</code> that wraps another exception.
+	 * 
+	 * @param errorCode The code of the error 
+	 * @param cause The cause of this exception.
+	 */
+	public ApplicationException(int errorCode, Throwable cause) {
+		super();
+		this.cause = cause;
+		this.errorCode = errorCode;
+	}
+
+	/**
+	 * Creates an <code>ApplicationException</code> with the specified error code.
+	 * @param errorCode The code of the error 
+	 * @param message The associated message
+	 */
+	public ApplicationException(int errorCode, String message) {
+		this(errorCode, message,null);
+	}
+
+	/**
+	 * Creates a <code>ApplicationException</code> that wraps another exception.
+	 * 
+	 * @param errorCode The code of the error 
+	 * @param message The associated message.
+	 * @param cause The cause of this exception.
+	 */
+	public ApplicationException(int errorCode, String message, Throwable cause) {
+		super(message);
+		this.cause = cause;
+		this.errorCode = errorCode;
+	}
+
+	/**
+	 * Returns the cause of this exception or <code>null</code> if no cause
+	 * was specified when this exception was created.
+	 * 
+	 * @return The cause of this exception or <code>null</code> if no cause
+	 *         was specified.
+	 */
+	public Throwable getCause() {
+		return cause;
+	}
+
+	/**
+	 * Returns the error code associcated with this exception.
+	 * @return The error code of this exception.
+	 */
+	public int getErrorCode() {
+		return errorCode;
+	}
+}