/*
 * 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 com.sun.jini.start;

import com.sun.jini.config.Config;

import net.jini.config.Configuration;
import net.jini.security.BasicProxyPreparer;
import net.jini.security.ProxyPreparer;

import java.io.InvalidObjectException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamException;
import java.rmi.activation.ActivationException;
import java.rmi.activation.ActivationGroupID;
import java.rmi.activation.ActivationID;
import java.rmi.activation.ActivationSystem;
import java.rmi.MarshalledObject;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Class used to launch shared, activatable services. 
 * Clients construct this object with the details
 * of the service to be launched, then call 
 * {@link #create(net.jini.config.Configuration) create(Configuration config) }
 * to launch the service in an existing  
 * {@linkplain SharedActivationGroupDescriptor shared activation group}
 * identified by the <code>sharedGroupLog</code> constructor parameter.
 * <P>
 * This class depends on {@link ActivateWrapper} to provide 
 * separation of the import codebase 
 * (where the service implementation classes are loaded from) 
 * from the export codebase 
 * (where service clients should load classes from, for example stubs) 
 * as well as providing an independent security policy file for each 
 * service object. This functionality allows multiple service objects 
 * to be placed in the same activation system group, with each object 
 * maintaining distinct export codebase and security policy settings. 
 * <P>
 * Services need to implement the "activatable" 
 * <A HREF="ActivateWrapper.html#serviceConstructor">constructor</A> 
 * required by {@link ActivateWrapper}. 
 * <P>
 * <A NAME="serviceProxy"></A>
 * A service implementation
 * can return its service proxy (via the <code>proxy</code> field of the 
 * {@link Created Created} object returned
 * by {@link #create(net.jini.config.Configuration) create})
 * in the following ways:
 * <DL>
 * <DT><A NAME="innerProxy">Return Inner Proxy</A></DT>
 * <DD><P>
 * The service's inner proxy is the 
 * {@link java.rmi.Remote} object returned from 
 * {@link java.rmi.activation.ActivationID#activate(boolean)} using
 * {@link ActivateWrapper} to "wrap" and register the desired service
 * with the activation system. 
 * A "wrapped" service's inner proxy is returned as follows:
 *
 * <UL>
 * <LI>If the newly created service instance implements {@link
 * net.jini.export.ProxyAccessor}, a proxy is obtained by invoking the {@link
 * net.jini.export.ProxyAccessor#getProxy getProxy} method on that instance. If the
 * obtained proxy is not <code>null</code>, that proxy is returned in a
 * {@link java.rmi.MarshalledObject}; otherwise, an
 * {@link java.io.InvalidObjectException} is thrown.
 *
 * <LI>If the newly created instance does not implement
 * {@link net.jini.export.ProxyAccessor}, the instance is returned in a
 * {@link java.rmi.MarshalledObject}.  In this case, the instance must be
 * serializable, and marshalling the instance must produce a suitable
 * proxy for the remote object (for example, the object implements
 * {@link java.io.Serializable} and defines a <code>writeReplace</code>
 * method that returns the object's proxy).
 * </UL>
 *
 * <P></DD>
 * <DT><A NAME="outerProxy">Return Outer Proxy</A></DT>
 * <DD><P>
 * The service's outer proxy is the object returned from invoking
 * {@link ServiceProxyAccessor#getServiceProxy()} on
 * the service's <A HREF="#innerProxy">inner proxy</A>. 
 * <P></DD>
 * </DL>
 *
 * The following items are discussed below:
 * <ul>
 * <li><a href="#configEntries">Configuring SharedActivatableServiceDescriptor</a>
 * <li><a href="#logging">Logging</a>
 * </ul>
 *
 * <a name="configEntries">
 * <h3>Configuring SharedActivatableServiceDescriptor</h3>
 * </a>
 *
 * <code>SharedActivatableServiceDescriptor</code> 
 * depends on {@link ActivateWrapper}, which can itself be configured. See
 * {@linkplain ActivateWrapper}'s 
 * <A HREF="ActivateWrapper.html#configEntries">configuration</A>
 * information for details.
 *<p>
 * This implementation obtains its configuration entries from the 
 * {@link net.jini.config.Configuration Configuration} object passed into 
 * the {@link #create(net.jini.config.Configuration) create} method.
 * The following configuration entries use the
 * component prefix "<code>com.sun.jini.start</code>": 
 * <p>
 *
 *   <table summary="Describes the activationIdPreparer configuration entry"
 *          border="0" cellpadding="2">
 *     <tr valign="top">
 *       <th scope="col" summary="layout"> <font size="+1">&#X2022;</font>
 *       <th scope="col" align="left" colspan="2"> <font size="+1"><code>
 *       activationIdPreparer</code></font>
 *     <tr valign="top"> <td> &nbsp <th scope="row" align="right">
 *       Type: <td> {@link net.jini.security.ProxyPreparer}
 *     <tr valign="top"> <td> &nbsp <th scope="row" align="right">
 *       Default: <td> <code>
 *         new {@link net.jini.security.BasicProxyPreparer}()
 *         </code>
 *     <tr valign="top"> <td> &nbsp <th scope="row" align="right">
 *       Description: <td> The proxy preparer for the service's activation
 *       ID. The value should not be <code>null</code>. 
 * 
 *       This class calls the 
 *       {@link java.rmi.activation.ActivationID#activate
 *       activate} method on instances of {@link
 *       java.rmi.activation.ActivationID} when they need to re/activate the
 *       service.
 *   </table>
 *
 *   <table summary="Describes the activationSystemPreparer configuration
 *          entry"
 *          border="0" cellpadding="2">
 *     <tr valign="top">
 *       <th scope="col" summary="layout"> <font size="+1">&#X2022;</font>
 *       <th scope="col" align="left" colspan="2"> <font size="+1"><code>
 *       activationSystemPreparer</code></font>
 *     <tr valign="top"> <td> &nbsp <th scope="row" align="right">
 *       Type: <td> {@link net.jini.security.ProxyPreparer}
 *     <tr valign="top"> <td> &nbsp <th scope="row" align="right">
 *       Default: <td> <code>
 *         new {@link net.jini.security.BasicProxyPreparer}()</code>
 *     <tr valign="top"> <td> &nbsp <th scope="row" align="right">
 *       Description: <td> The proxy preparer for the proxy for the
 *       activation system. The value should not be <code>null</code>. 
 * 
 *       The service starter calls the {@link
 *       java.rmi.activation.ActivationSystem#unregisterObject
 *       unregisterObject} method on the {@link
 *       java.rmi.activation.ActivationSystem} when there is a problem
 *       creating a service.
 *   </table>
 * 
 * <a name="servicePreparer">
 * <table summary="Describes the default service preparer configuration entry"
 *        border="0" cellpadding="2">
 *    <tr valign="top">
 *      <th scope="col" summary="layout"> <font size="+1">&#X2022;</font>
 *      <th scope="col" align="left" colspan="2"> <font size="+1"><code>
 *      servicePreparer</code></font>
 *    <tr valign="top"> <td> &nbsp <th scope="row" align="right">
 *      Type: <td> {@link net.jini.security.ProxyPreparer}
 *    <tr valign="top"> <td> &nbsp <th scope="row" align="right">
 *      Default: <td> <code>
 *        new {@link net.jini.security.BasicProxyPreparer}()
 *        </code>
 *    <tr valign="top"> <td> &nbsp <th scope="row" align="right">
 *      Description: <td> The default proxy preparer used to prepare
 *      service proxies.
 *      This value should not be <code>null</code>. This entry is
 *      obtained during the invocation of 
 *      {@link #create(net.jini.config.Configuration) create} and is used, 
 *      to prepare the <A HREF="#innerProxy">inner</A> and 
 *      <A HREF="#outerProxy">outer</A> service proxies returned by 
 *      the service implementation 
 *      (see <a href="#serviceProxy">service proxy</a> section for details).
 *      This entry is superseded by explicitly passing a 
 *      {@link ProxyPreparer ProxyPreparer} to one of the constructors that
 *      accept a {@linkplain ProxyPreparer proxy preparer} argument. 
 *  </table>
 *
 *<a name="logging">
 *<h3>Loggers and Logging Levels</h3>
 *</a>
 *
 * The implementation uses the {@link
 * java.util.logging.Logger}, named 
 * <code>com.sun.jini.start.service.starter</code>. 
 * The following table describes the
 * type of information logged as well as the levels of information logged.
 * <p>
 *
 *  <table border="1" cellpadding="5"
 *	 summary="Describes logging performed by the shared,
 *       activatable service descriptor at different
 *	 logging levels">
 *
 *  <caption halign="center" valign="top"><b><code>
 *	   com.sun.jini.start.service.starter</code></b></caption>
 *
 *  <tr> <th scope="col"> Level <th scope="col"> Description
 *
 *  <tr> <td> {@link java.util.logging.Level#FINER FINER} <td> 
 *    for high level
 *    service operation tracing
 *  <tr> <td> {@link java.util.logging.Level#FINEST FINEST} <td> 
 *    for low level
 *    service operation tracing
 *
 *  </table> <p>
 * 
 * 
 * @since 2.0
 *
 */

public class SharedActivatableServiceDescriptor 
    extends NonActivatableServiceDescriptor
{
    private static final long serialVersionUID = 1L;
    
    /**
     * @serial <code>String</code> representing the directory where 
     *     the associated shared group identifier information is persisted
     */
    private final String sharedGroupLog;

    /**
     * @serial <code>boolean</code> flag passed through as the 
     *     <code>restart</code> parameter to the  
     *     {@linkplain java.rmi.activation.ActivationDesc#ActivationDesc(java.rmi.activation.ActivationGroupID, java.lang.String, java.lang.String, java.rmi.MarshalledObject, boolean)
     *     ActivationDesc constructor} used to register the service with the 
     *     activation system.
     */
    private final boolean restart;

    /**
     * @serial <code>String</code> containing hostname of desired 
     *     activation system.
     */
    private final String host;

    /**
     * @serial <code>int</code> representing port of desired activation system.
     */
    private final int port;

    private static final Logger logger = ServiceStarter.logger;
    
    /*
     * <code>ProxyPreparer</code> reference for preparing the service's proxy
     * returned from the call to 
     * {@linkplain java.rmi.activation.ActivationID#activate(boolean) activate}.
     * If this "inner" proxy implements
     * {@linkplain ServiceProxyAccessor ServiceProxyAccessor} it will then be used to invoke
     * {@linkplain ServiceProxyAccessor#getServiceProxy() getServiceProxy}.
     */
    private /*final*/ transient ProxyPreparer innerProxyPreparer;
    
    /** 
     * Object returned by 
     * {@link SharedActivatableServiceDescriptor#create(net.jini.config.Configuration) 
     * SharedActivatableServiceDescriptor.create()}
     * method that returns the associated proxy, activation group 
     * identifier, and activation identifier
     * for the created service.
     */
    public static class Created {
        /** The activation group id of the group hosting the service */
        public final ActivationGroupID gid;
        /** The activation id of the service */
        public final ActivationID aid;
        /** The reference to the proxy of the created service */
	public final Object proxy;
        /** Constructs an instance of this class.
         * @param gid   activation group id of the created service
         * @param aid   activation id of the created service
         * @param proxy reference to the proxy of the created service
         */
        public Created(ActivationGroupID gid, ActivationID aid, Object proxy) {
            this.gid   = gid;
            this.aid   = aid;
            this.proxy = proxy;
        }//end constructor
    }//end class Created

    
    /**
     * Convenience constructor. Equivalent to calling this 
     * {@link #SharedActivatableServiceDescriptor(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String[], net.jini.security.ProxyPreparer, net.jini.security.ProxyPreparer, boolean, java.lang.String, int) constructor}
     * with the <code>innerProxyPreparer</code>, <code>outerProxyPreparer</code> 
     * and <code>host</code> arguments set to 
     * <code>null</code> 
     * and the <code>port</code> argument set to 
     * the currently configured activation system port.
     * The activation system port defaults to  
     * {@link ActivationSystem#SYSTEM_PORT} unless it is overridden by the
     * <code>java.rmi.activation.port</code> system property.
     * 
     */
    public SharedActivatableServiceDescriptor(
	// Required Args
	String exportCodebase,
	String policy, 
	String importCodebase,
	String implClassName,
	String sharedGroupLog,
	// Optional Args,
	String[] serverConfigArgs,
	boolean restart) 
    {
        this(exportCodebase, policy, importCodebase, implClassName, 
	     sharedGroupLog, serverConfigArgs, null,
             null, restart, null, ServiceStarter.getActivationSystemPort());
    }
    
    /**
     * Convenience constructor. Equivalent to calling this 
     * {@link #SharedActivatableServiceDescriptor(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String[], net.jini.security.ProxyPreparer, net.jini.security.ProxyPreparer, boolean, java.lang.String, int) constructor}
     * with the <code>host</code> argument set to 
     * <code>null</code> and the <code>port</code> argument set to the 
     * currently configured activation system port.
     * The activation system port defaults to  
     * {@link ActivationSystem#SYSTEM_PORT} unless it is overridden by the
     * <code>java.rmi.activation.port</code> system property.
     * 
     */
    public SharedActivatableServiceDescriptor(
	// Required Args
	String exportCodebase,
	String policy, 
	String importCodebase,
	String implClassName,
	String sharedGroupLog,
	// Optional Args,
	String[] serverConfigArgs,
        ProxyPreparer innerProxyPreparer,
        ProxyPreparer outerProxyPreparer,
	boolean restart) 
    {
        this(exportCodebase, policy, importCodebase, implClassName, 
	     sharedGroupLog, serverConfigArgs, innerProxyPreparer,
             outerProxyPreparer, restart, null, ServiceStarter.getActivationSystemPort());
    }
    
     /**
     * Convenience constructor. Equivalent to calling this 
     * {@link #SharedActivatableServiceDescriptor(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String[], net.jini.security.ProxyPreparer, net.jini.security.ProxyPreparer, boolean, java.lang.String, int) constructor}
     * with the <code>innerProxyPreparer</code> and <code>outerProxyPreparer</code> arguments set to 
     * <code>null</code>.
     */
    public SharedActivatableServiceDescriptor(
	// Required Args
	String exportCodebase,
	String policy, 
	String importCodebase,
	String implClassName,
	String sharedGroupLog,
	// Optional Args,
	String[] serverConfigArgs,
	boolean restart,
	String host,
	int port) 
    {
        this(exportCodebase, policy, importCodebase, implClassName, 
	     sharedGroupLog, serverConfigArgs, null, null, restart,
	     host, port);
    }
    
    /**
     * Main constructor. Simply assigns given parameters to 
     * their associated, internal fields unless otherwise noted.
     * 
     * @param exportCodebase location where clients can download required
     *     service-related classes (for example, stubs, proxies, etc.).
     *     Codebase components must be separated by spaces in which 
     *     each component is in <code>URL</code> format. 
     * @param policy server policy filename or URL
     * @param importCodebase location where server implementation
     *     classes can be found. 
     *     This <code>String</code> assumed (in order) to be either
     *     1) a space delimited set of <code>URL</code>(s)
     *     representing a codebase or
     *     2) a <code>File.pathSeparator</code> delimited set 
     *     of class paths.
     * @param implClassName name of server implementation class
     * @param sharedGroupLog location where the associated shared 
     *     group identifier information is persisted
     * @param serverConfigArgs service configuration arguments
     * @param innerProxyPreparer <code>ProxyPreparer</code> reference. This object
     *     will be used to prepare the service's <A HREF="#innerProxy">inner proxy</A>.
     *     If the inner proxy implements
     *     {@link ServiceProxyAccessor} 
     *     it will then be used to invoke
     *     {@link ServiceProxyAccessor#getServiceProxy()} in order to get the
     *     service's <A HREF="#outerProxy">outer proxy</A>.
     * @param outerProxyPreparer <code>ProxyPreparer</code> reference. This object
     *     will be used to prepare the service's 
     *     <A HREF="#outerProxy">outer proxy</A> before it is returned to the caller of
     *     {@link SharedActivatableServiceDescriptor#create(net.jini.config.Configuration)}.
     * @param restart boolean flag passed through as the 
     *     <code>restart</code> parameter to the  
     *     {@linkplain java.rmi.activation.ActivationDesc#ActivationDesc(java.rmi.activation.ActivationGroupID, java.lang.String, java.lang.String, java.rmi.MarshalledObject, boolean)
     *     ActivationDesc constructor} used to register the service with the 
     *     activation system.
     * @param host hostname of desired activation system. If <code>null</code>,
     *     defaults to the localhost.  
     * @param port port of desired activation system. If value is <= 0, then
     *     defaults to  
     *     {@link java.rmi.activation.ActivationSystem#SYSTEM_PORT 
     *     ActivationSystem.SYSTEM_PORT}.
     */
    public SharedActivatableServiceDescriptor(
	// Required Args
	String exportCodebase,
	String policy, 
	String importCodebase,
	String implClassName,
	String sharedGroupLog,
	// Optional Args,
	String[] serverConfigArgs,
        ProxyPreparer innerProxyPreparer,
        ProxyPreparer outerProxyPreparer,        
	boolean restart,
	String host,
	int port) 
    {
	super(exportCodebase, policy, importCodebase, implClassName, 
	      serverConfigArgs, outerProxyPreparer);
	if ( sharedGroupLog == null)
            throw new NullPointerException(
		"Shared VM log cannot be null");
	this.sharedGroupLog = sharedGroupLog;
	this.restart = restart;
	this.host = (host == null) ? "" : host;
	this.port = 
	    (port <= 0) ? ServiceStarter.getActivationSystemPort() : port;
        this.innerProxyPreparer = innerProxyPreparer;
    }
    
    /**
     * Shared group log accessor method.
     *
     * @return the Shared group log associated with this service descriptor.
     */
    final public String getSharedGroupLog() { return sharedGroupLog; }
    
    /**
     * Restart accessor method.
     *
     * @return the restart mode associated with this service descriptor.
     */
    final public boolean getRestart() { return restart; }
    
    /**
     * Activation system host accessor method.
     *
     * @return the activation system host associated with 
     *     this service descriptor.
     */
    final public String getActivationSystemHost() { return host; }
    
    /**
     * Activation system port accessor method.
     *
     * @return the activation system port associated with this service descriptor.
     */
    final public int getActivationSystemPort() { return port; } 
    
    /**
     * <code>ProxyPreparer</code> accessor method.
     *
     * @return the <A HREF="#innerProxy">inner proxy</A> preparer associated with 
     * this service descriptor.
     */
    final public ProxyPreparer getInnerProxyPreparer() { return innerProxyPreparer; }

    /**
     * Sets the <A HREF="#innerProxy">inner</A> 
     * <code>ProxyPreparer</code> for this descriptor.
     * This needs to 
     * be called on the service descriptor prior to calling 
     * <code>create()</code>. Useful for (re-)setting the
     * the associated inner <code>ProxyPreparer</code> upon deserialization of
     * the descriptor.
     *
     * @param pp The inner <code>ProxyPreparer</code> object to be
     * associated with this service descriptor. 
     *
     * @throws IllegalStateException if called after <code>create()</code> is invoked
     */
     final public void setInnerProxyPreparer(ProxyPreparer pp) { 
        synchronized (descCreatedLock) {
	    if (descCreated) {
	        throw new IllegalStateException("Can't set ProxyPreparer after descriptor creation");
	    } else {
		innerProxyPreparer = pp; 
	    }
	}
    }
     
    /**
     * Method that attempts to create a service based on the service 
     * description information provided via constructor parameters.
     * <P>
     * This method:
     * <UL>
     * <LI> creates an <code>ActivateWrapper.ActivateDesc</code> with
     *      the provided constructor parameter information for the 
     *      desired service
     * <LI> retrieves the 
     *      {@linkplain java.rmi.activation.ActivationGroupID group identifier}
     *      associated with the provided shared group log.
     * <LI> invokes 
     *      {@link ActivateWrapper#register(java.rmi.activation.ActivationGroupID, com.sun.jini.start.ActivateWrapper.ActivateDesc, boolean, java.rmi.activation.ActivationSystem)
     *      ActivateWrapper.register()} with the provided information.
     * <LI> obtains an <A HREF="#innerProxy">inner proxy</A> by calling 
     *      {@link java.rmi.activation.ActivationID#activate(boolean)
     *      activate(true)} on the object returned from 
     *      <code>ActivateWrapper.register()</code>, which also
     *      activates the service instance.
     * <LI> obtains the service proxy in the following 
     *      order of precedence:
     *      <UL>
     *      <LI>if the <A HREF="#innerProxy">inner proxy</A> implements
     *      {@link ServiceProxyAccessor} then the return value of
     *      {@link ServiceProxyAccessor#getServiceProxy() getServiceProxy}
     *      is used
     *      <LI>if the <A HREF="#innerProxy">inner proxy</A> is 
     *      not <code>null</code> then it is used
     *      <LI>Otherwise, <code>null</code> is used
     * </UL>
     *
     * @return a 
     *      {@link com.sun.jini.start.SharedActivatableServiceDescriptor.Created
     *      Created} object that contains the group identifier, activation ID, and
     *      proxy associated with the newly created service instance.
     * @throws java.lang.Exception Thrown if there was any problem 
     *     creating the object.
     *
     */
    public Object create(Configuration config) throws Exception {
        ServiceStarter.ensureSecurityManager();
        logger.entering(SharedActivatableServiceDescriptor.class.getName(),
	    "create", new Object[] {config});

        if (config == null) {
           throw new NullPointerException(
               "Configuration argument cannot be null");
        }
            
        ProxyPreparer globalServicePreparer =
            (ProxyPreparer) Config.getNonNullEntry(config,
	        ServiceStarter.START_PACKAGE, 
		"servicePreparer", ProxyPreparer.class,
                new BasicProxyPreparer());
        
        // Needs to be called prior to setting the "descCreated" flag
        if (getServicePreparer() == null) {
            setServicePreparer(globalServicePreparer);
        }	
        
        synchronized (descCreatedLock) {
	    descCreated = true;
	}
		
	// Get prepared activation system reference
	Created created = null;
	ActivationSystem sys = 
	    ServiceStarter.getActivationSystem(
	        getActivationSystemHost(),
		getActivationSystemPort(),
		config);
        ProxyPreparer activationIDPreparer =
            (ProxyPreparer) Config.getNonNullEntry(config,
	        ServiceStarter.START_PACKAGE, "activationIdPreparer", 
		ProxyPreparer.class, new BasicProxyPreparer());

        if (innerProxyPreparer == null) {
            innerProxyPreparer = globalServicePreparer;
        }
        
	/* Warn user of inaccessible codebase(s) */
        HTTPDStatus.httpdWarning(getExportCodebase());

        ActivationGroupID gid      = null;
        ActivationID aid           = null;
        Object proxy               = null;
        try {
            /* Create the ActivateWrapper descriptor for the desired service */
            MarshalledObject params = 
	        new MarshalledObject(getServerConfigArgs());
            ActivateWrapper.ActivateDesc adesc =
                new ActivateWrapper.ActivateDesc(
                    getImplClassName(),
                    ClassLoaderUtil.getImportCodebaseURLs(getImportCodebase()),
                    ClassLoaderUtil.getCodebaseURLs(getExportCodebase()),
                    getPolicy(),
                    params);
	    logger.finest("ActivateDesc: " + adesc);
            // Get hosting activation group
            gid = SharedActivationGroupDescriptor.restoreGroupID(
		getSharedGroupLog());

            /* Register the desired service with the activation system */
            aid = ActivateWrapper.register(
	        gid, adesc, getRestart(), sys);
            aid = (ActivationID) activationIDPreparer.prepareProxy(aid);
		
            proxy = aid.activate(true);

	    if(proxy != null) {
                proxy = innerProxyPreparer.prepareProxy(proxy);
	        if (proxy instanceof ServiceProxyAccessor) {
                    proxy = ((ServiceProxyAccessor)proxy).getServiceProxy();
                    if(proxy != null) {
                        proxy = getServicePreparer().prepareProxy(proxy);
                    } else {
                        logger.log(Level.FINE, 
		            "Service's getServiceProxy() returned null");
                    }
		}
            }//endif
        } catch(Exception e) {
            try {
	        if (aid != null) sys.unregisterObject(aid);
            } catch (Exception ee) {
                // ignore -- did the best we could.
		logger.log(Level.FINEST, 
		    "Unable to unregister with activation system", ee);
            }
            if (e instanceof IOException) 
	        throw (IOException)e;
	    else if (e instanceof ActivationException)
	        throw (ActivationException)e;
	    else if (e instanceof ClassNotFoundException)
	        throw (ClassNotFoundException)e;
	    else 
	        throw new RuntimeException("Unexpected Exception", e);
	} 
        created = new Created(gid, aid, proxy);
	logger.exiting(SharedActivatableServiceDescriptor.class.getName(), 
	    "create", created);
	return created;
    }
    
    public String toString() {
        // Would like to call super(), but need different formatting
        ArrayList fields = new ArrayList(12);
	fields.add(getExportCodebase());
	fields.add(getPolicy());
	fields.add(getImportCodebase());
	fields.add(getImplClassName());
	fields.add(
            ((getServerConfigArgs() == null) 
                ? null : Arrays.asList(getServerConfigArgs())));
        fields.add(getLifeCycle());
	fields.add(getServicePreparer());
	fields.add(getInnerProxyPreparer());
        fields.add(sharedGroupLog);
	fields.add(Boolean.valueOf(restart));
	fields.add(host);
	fields.add(Integer.valueOf(port));
        return fields.toString();
    }
    
    /**
     * Reads the default serializable field values for this object.  
     * Also, verifies that the deserialized values are legal.
     */
    private void readObject(ObjectInputStream in) 
        throws IOException, ClassNotFoundException 
    {
        in.defaultReadObject();
	// Verify serialized fields
	if (sharedGroupLog == null) {
	    throw new InvalidObjectException("null shared group log");
	}
	if (host == null) {
	    throw new InvalidObjectException("null activation host name");
	}
	if (port <= 0) {
	    throw new InvalidObjectException("invalid activation port value: " + port);
	}
        
	//Reinitialize transient fields upon de-serialization.
        innerProxyPreparer = null;        
    }
    
    /**
     * Throws InvalidObjectException, since data for this class is required.
     */
    private void readObjectNoData() throws ObjectStreamException {
	throw new InvalidObjectException("no data");
    }
}


