/*
 * $Header: /cvsroot/eclipse/org.eclipse.equinox.app/src/org/osgi/service/application/ApplicationHandle.java,v 1.4 2006/09/15 14:46:00 twatson 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 org.osgi.framework.Constants;

/**
 * ApplicationHandle is an OSGi service interface which represents an instance
 * of an application. It provides the functionality to query and manipulate the
 * lifecycle state of the represented application instance. It defines constants
 * for the lifecycle states.
 */
public abstract class ApplicationHandle {
	/*
	 * 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 unique identifier (PID) of the application
	 * instance.
	 */
	public static final String APPLICATION_PID = Constants.SERVICE_PID;
	
	/**
	 * The property key for the pid of the corresponding application descriptor.
	 */
	public final static String APPLICATION_DESCRIPTOR	= "application.descriptor";
	
	/**
	 * The property key for the state of this appliction instance.
	 */
	public final static String APPLICATION_STATE		= "application.state";

	/**
	 * The application instance is running. This is the initial state of a newly
	 * created application instance.
	 */
	public final static String RUNNING = "RUNNING";
	
  /**
   * The application instance is being stopped. This is the state of the
   * application instance during the execution of the <code>destroy()</code>
   * method.
   */
	public final static String STOPPING = "STOPPING";

	private final String instanceId;
	
	private final ApplicationDescriptor	descriptor;

	/**
	 * Application instance identifier is specified by the container when the
	 * instance is created. The instance identifier must remain static for the 
	 * lifetime of the instance, it must remain the same even across framework
	 * restarts for the same application instance. This value must be the same
	 * as the <code>service.pid</code> service property of this application
	 * handle.
	 * <p>
	 * The instance identifier should follow the following scheme: 
	 * &lt;<i>application descriptor PID</i>&gt;.&lt;<i>index</i>&gt;
	 * where &lt;<i>application descriptor PID</i>&gt; is the PID of the 
	 * corresponding <code>ApplicationDescriptor</code> and &lt;<i>index</i>&gt;
	 * is a unique integer index assigned by the application container. 
	 * Even after destroying the application index the same index value should not
	 * be reused in a reasonably long timeframe.
	 * 
	 * @param instanceId the instance identifier of the represented application
	 * instance. It must not be null.
	 * 
	 * @param descriptor the <code>ApplicationDescriptor</code> of the represented
	 * application instance. It must not be null.
	 * 
	 * @throws NullPointerException if any of the arguments is null.
	 */
	protected ApplicationHandle(String instanceId, ApplicationDescriptor descriptor ) {
		if( (null == instanceId) || (null == descriptor) ) {
			throw new NullPointerException("Parameters must not be null!");
		}
		
		this.instanceId	= instanceId;
		this.descriptor = descriptor;
	}

	/**
	 * Retrieves the <code>ApplicationDescriptor</code> to which this 
	 * <code>ApplicationHandle</code> belongs. 
	 * 
	 * @return The corresponding <code>ApplicationDescriptor</code>
	 */
	public final ApplicationDescriptor getApplicationDescriptor() {
		return descriptor;
	}

	/**
	 * Get the state of the application instance.
	 * 
	 * @return the state of the application.
	 * 
	 * @throws IllegalStateException
	 *             if the application handle is unregistered
	 */
	public abstract String getState();

	/**
	 * Returns the unique identifier of this instance. This value is also
	 * available as a service property of this application handle's service.pid.
	 * 
	 * @return the unique identifier of the instance
	 */
	public final String getInstanceId() {
		return instanceId;
	}

	/**
	 * The application instance's lifecycle state can be influenced by this
	 * method. It lets the application instance perform operations to stop
	 * the application safely, e.g. saving its state to a permanent storage.
	 * <p>
	 * The method must check if the lifecycle transition is valid; a STOPPING
	 * application cannot be stopped. If it is invalid then the method must
	 * exit. Otherwise the lifecycle state of the application instance must be
	 * set to STOPPING. Then the destroySpecific() method must be called to
	 * perform any application model specific steps for safe stopping of the
	 * represented application instance.
	 * <p>
	 * At the end the <code>ApplicationHandle</code> must be unregistered. 
	 * This method should  free all the resources related to this 
	 * <code>ApplicationHandle</code>.
	 * <p>
	 * When this method is completed the application instance has already made
	 * its operations for safe stopping, the ApplicationHandle has been
	 * unregistered and its related resources has been freed. Further calls on
	 * this application should not be made because they may have unexpected
	 * results.
	 * 
	 * @throws SecurityException
	 *             if the caller doesn't have "lifecycle"
	 *             <code>ApplicationAdminPermission</code> for the corresponding application.
	 * 
	 * @throws IllegalStateException
	 *             if the application handle is unregistered
	 */
	public final void destroy() {
		if (STOPPING.equals(getState()))
			return;
		SecurityManager sm = System.getSecurityManager();
		if (sm != null)
			sm.checkPermission(new ApplicationAdminPermission(getApplicationDescriptor(), ApplicationAdminPermission.LIFECYCLE_ACTION));
		destroySpecific();
	}

	/**
	 * Called by the destroy() method to perform application model specific
	 * steps to stop and destroy an application instance safely.
	 * 
	 * @throws IllegalStateException
	 *             if the application handle is unregistered
	 */
	protected abstract void destroySpecific();
	

}
