/*
* Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/
package com.nokia.mj.impl.rt.support;
import java.security.AccessControlException;
import java.security.Permission;
import java.util.Enumeration;
import java.util.Vector;
import com.nokia.mj.impl.utils.Uid;
import com.nokia.mj.impl.utils.Logger;
/**
* ApplicationUtils is an abstract base class for API implementations,
* which allows them to use miscellanous utilities related to the running
* application.
* <p>
* The class provides a static getter method for getting an instance of
* the running application. In those runtimes that are always running only
* one instance (like MIDP) returns always the same instance of the
* ApplicationUtils. However those runtimes (like eRCP), that may run several
* application in the same JVM instance, will return an application specific
* instance.
* <p>
* The runtime implementation hides the solving of the correct application
* when method <code>getInstace</code> is called. However it must be noted
* that if the call is made some common thread, the <code>getInstace</code>
* might not able to solve the correct application.
* <p>
* Example how to register a shutdown listener.
* <pre>
* package com.nokia.mj.impl.mypackage;
*
* import com.nokia.mj.impl.rt.support.ApplicationUtils;
* import com.nokia.mj.impl.rt.support.ShutdownListener;
* public MyClass
* {
* public void myMethod()
* {
* // Get the instance of ApplicationUtils.
* ApplicationUtils appUtils = ApplicationUtils.getInstance();
*
* // Get the name of the application.
* appUtils.addShutdownListener(new ShutdownListener()
* {
* public void shuttingDown()
* {
* //Do cleaning...
* }
*
* });
*
*
* // My implementation...
* }
* }
*</pre>
* @author Nokia Corporation
* @version 1.0
*/
public abstract class ApplicationUtils
{
/**
* Name of the runtime specific class that extends this base class.
*/
private static final String PORTCLASS = ".ApplicationUtilsImpl";
/**
* A singleton instance of runtime dependent instance of class extending
* the ApplicationUtils base class.
*/
protected static ApplicationUtils sInstance = null;
/**
* A set of listeners who wants to receive notification when the
* application is abaout to close.
*/
private Vector mListeners;
/**
* A lock for synchronizing the thw start up waiting feature.
*/
private Object mApplicationStartLock = new Object();
/**
* Information wheteher to continue start up or cancel it.
*/
private Boolean mStartCmd;
/**
* When this class is first loaded the static initializer will create a
* singleton instance of runtime dependent instance of class extending the
* ApplicationUtils base class. The class is created using dynamic
* instantiation (<code>Class.forname & Class.newInstance</code>) and
* the name of the class is a combination of PACKAGE_PREFIX +
* <value of system property PACKAGE_END_PROPERTY_NAME >
* + .<value of PORTCLASS member variable >.
*/
static
{
//Get the system proptery defining the end of package.
String packageEnd =
System.getProperty(ApplicationInfo.PACKAGE_END_PROPERTY_NAME);
if (packageEnd == null)
{
throw new RuntimeException
("Not able to load " + PORTCLASS + "class since " +
ApplicationInfo.PACKAGE_END_PROPERTY_NAME +
" system property is undefined");
}
//Construct the class
String className = ApplicationInfo.PACKAGE_PREFIX +
packageEnd + PORTCLASS;
try
{
Class clazz = Class.forName(className);
sInstance = (ApplicationUtils)clazz.newInstance();
}
catch (Throwable t)
{
String err = "Not able to instantiate class " +
className + ". Reason is: ";
Logger.LOG(Logger.EUtils, Logger.EInfo, err, t);
throw new RuntimeException(err + t);
}
}
/**
* Returns an instace of ApplicationUtils class which provides access to
* application related runtime services.
*
* @return the ApplicationUtils object, null if the construction of the
* object has faild
*/
public static ApplicationUtils getInstance()
{
return sInstance;
}
/**
* Notifies the runtime that an exit command has been received and the
* application is being tried to close nicely. The runtime is responsible
* for killing the application if it doesn't close itself nicely after
* specified grace time. The specified grace time is runtime dependent.
* <p>
* This method is meant ONLY for the UI and no other API are allowed
* to use it. The UI must use this API ONLY when the user explicitly
* wants to close the application using some platform dependent feature
* (e.g. red key in S60). If the user tries to close the application
* using the mechanism provided by the application itself, this method
* must not be called.
* <p>
* Note that calling this method might cause the UI framework to call
* uiDisposed method, depending on which UI framework is used.
* <p>
* This method is a problematic in such runtimes that may run more than one
* application in same JVM instance (e.g. eRCP). If the application
* doesn't close nicely the runtime may have to terminate
* the whole JVM process, which leads closing all the running applications
* and the runtime itself.
*
*/
public abstract void notifyExitCmd();
/**
* Notifies the runtime that UI has been disposed. The runtime is
* responsible for killing the application if it doesn't close itself
* nicely after specified grace time. The specified grace time is
* runtime dependent.
* <p>
* This method is meant ONLY for the UI and no other API are allowed
* to use it.
* <p>
* It is possible that the method is called several times from different
* phases of the UI exit sequence.
*/
public void uiDisposed()
{
notifyExitCmd();
}
/**
* Determines whether the access request indicated by the specified
* permission should be allowed or denied, based on the security policy
* currently in effect. This method quietly returns if the access request
* is permitted, or throws a suitable AccessControlException otherwise.
* <p>
* The design decision was that all the API implementation should use this
* method for making security checkings and avoid using the
* <code>checkPermission</code> method <code>AccessController</code> class,
* which is left for application usage only.
* <p>
* The runtime implementation is responsible for forwarding security
* checking to correct securty handler. In MIDP this would be Midp security
* component while in 'main' type of application the handler would be the
* <code>AccessController</code> class.
*
* @param p the requested permission.
* @throws AccessControlException if the specified permission is not
* permitted, based on the current security policy.
* @throws NullPointerException if the specified permission is null.
*/
public abstract void checkPermission(Permission p)
throws AccessControlException,
NullPointerException;
public abstract void checkPermission(Uid appUid,Permission p)
throws AccessControlException,
NullPointerException;
/**
* Adds a shutdown notifications listener to receive notifications when
* the application is about to close.
* <p>
* When the runtime receives information that the application is closing
* (either from the application itself or from the system) the runtime
* will send a notification to all registered listeners by calling
* {@link ShutdownListener#shuttingDown() shuttingDown} method. All the
* calls are made in a loop in one thread, so if some listener blocks the
* call the rest of the listeners don't get the notification.
* <p>
* There can be more than one listener, but it is recommended that there
* is only one listener per component.
* <p>
* The implementation stores a strong reference to object which prevents
* garbage collection of the listener unless the listener is removed.
*
* @param listener the new listener.
*/
public void addShutdownListener(ShutdownListener listener)
{
if (mListeners == null)
{
mListeners = new Vector();
}
mListeners.addElement(listener);
}
/**
* Removes the registered shutdown listener.
*
* @param listener the listener to be removed. If the listener is not
* found nothing happens. If the key is null, a
* @throws NullPointerException if the listener is null.
*/
public void removeShutdownListener(ShutdownListener listener)
{
if (listener == null)
{
throw new
NullPointerException("Listener was null when trying to remove");
}
if (mListeners != null)
{
mListeners.removeElement(listener);
}
}
/**
* Waits (if needed) until the application to be started is known.
* This method can be used for pre-warming features. If the runtime is in
* pre-warmed state where the application to be launched is not yet known,
* this method will block. It is safe to call this method if the application
* is already known - in that case the method won't block. Once the
* application is known all the waiters will be released. Knowing the
* application doesn't necessarily mean that the application it self
* has been created (might happen later). The method will provide info
* whether to continue or cancel the start up as a return value.
* @return true if the user should continue starting, otherwise the user
* should do the required shut down proceures.
*/
public boolean waitStart()
{
synchronized (mApplicationStartLock)
{
if (mStartCmd == null)
{
try
{
mApplicationStartLock.wait();
}
catch (InterruptedException ie)
{
}
}
return mStartCmd == null ? false : mStartCmd.booleanValue();
}
}
/**
* Can be used to inform the runtime to pause the running application. The
* origin could be e.g. flip close or application going to back ground.
*/
public void pauseApplication()
{
// Empty implementation as default.
}
/**
* Can be used to inform the runtime to resume the paused application. The
* origin could be e.g. flip open or application going to fore ground.
*/
public void resumeApplication()
{
// Empty implementation as default.
}
/**
* Releases the start waiters.
*/
protected void releaseStartWaiter(boolean doStart)
{
if (mApplicationStartLock != null)
{
synchronized (mApplicationStartLock)
{
mStartCmd = new Boolean(doStart);
mApplicationStartLock.notifyAll();
}
}
}
/**
* Sends shutdown notification to all the registered listeners.
*/
protected void doShutdown()
{
if (mListeners != null)
{
Enumeration enumer = mListeners.elements();
while (enumer.hasMoreElements())
{
ShutdownListener listener =
(ShutdownListener)enumer.nextElement();
listener.shuttingDown();
}
}
mListeners = null;
}
}