/**
 * Copyright (c) Unpublished Work of Novell, Inc. All Rights Reserved.
 * THIS WORK IS AN UNPUBLISHED WORK AND CONTAINS CONFIDENTIAL,
 * PROPRIETARY AND TRADE SECRET INFORMATION OF NOVELL, INC. ACCESS TO
 * THIS WORK IS RESTRICTED TO (I) NOVELL, INC. EMPLOYEES WHO HAVE A
 * NEED TO KNOW HOW TO PERFORM TASKS WITHIN THE SCOPE OF THEIR
 * ASSIGNMENTS AND (II) ENTITIES OTHER THAN NOVELL, INC. WHO HAVE
 * ENTERED INTO APPROPRIATE LICENSE AGREEMENTS. NO PART OF THIS WORK
 * MAY BE USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED, REVISED,
 * MODIFIED, TRANSLATED, ABRIDGED, CONDENSED, EXPANDED, COLLECTED,
 * COMPILED, LINKED, RECAST, TRANSFORMED OR ADAPTED WITHOUT THE PRIOR
 * WRITTEN CONSENT OF NOVELL, INC. ANY USE OR EXPLOITATION OF THIS
 * WORK WITHOUT AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO
 * CRIMINAL AND CIVIL LIABILITY.
 *
 * %version:  %
 * %created_by:  %
 * %date_modified: %
 */

package com.novell.nds.dirxml.driver.xds.skeleton;


import com.novell.nds.dirxml.driver.Trace;
import com.novell.nds.dirxml.driver.xds.*;

import java.util.List;
import java.util.ListIterator;
import java.util.Map;


/**
 * Common implementation for the Skeleton Driver.
 * 
 * <p>
 * This class contains common methods and fields used in the DriverShim,
 * PublicationShim, and SubscriptionShim implementations of the Skeleton
 * Driver.
 * </p>
 */
public abstract class CommonImpl
{
    //~ Static fields/initializers ---------------------------------------------

    //these constants are used to construct a <source> element in
    //  documents sent to the DirXML engine:
    // MODIFY:  put your driver's name here

    /** The name of your driver. */
    private static final String PRODUCT_NAME = "DirXML Skeleton Driver (Java, XDS)";

    // MODIFY:  put your company name here

    /** Your company name. */
    private static final String COMPANY_NAME = "My Company Name";

    // MODIFY:  put the marketing version of your driver here

    /** The marketing version of this driver. */
    private static final String VERSION = XDS.VERSION;

    //MODIFY:  put a temporary driver identifier here

    /**
     * A temporary trace identifier for this driver.
     * 
     * <p>
     * Temporarily identifies this driver in trace messages until the driver's
     * RDN is known.
     * </p>
     */
    protected static final String TRACE_ID = "Skeleton Driver";

    //~ Instance fields --------------------------------------------------------

    /**
     * Container for driver parameters passed to
     * <code>SkeletonDriverShim.init(XmlDocument)</code>.
     * 
     * <p>
     * Contains shared authentication parameters.
     * </p>
     * 
     * <p></p>
     *
     * @see SkeletonDriverShim#init(com.novell.nds.dirxml.driver.XmlDocument)
     * @see SkeletonDriverShim#setDriverParams()
     */
    protected Map driverParams;

    /** This driver's Relative Distinguished Name (RDN). */
    protected String driverRDN;

    /**
     * Used by derived classes to output trace messages to DSTrace or a Java
     * trace file.
     * 
     * <p>
     * To cause trace messages to appear on the DSTrace screen set <code>the
     * DirXML-DriverTraceLevel</code> attribute on the driver set object to a
     * value greater than zero. To log trace messages to a file, set the
     * <code>DirXML-JavaTraceFile</code> attribute on the driver set object to
     * a file path.
     * </p>
     */
    protected Trace trace;

    /**
     * Connection state.
     * 
     * <p></p>
     *
     * @see SkeletonSubscriptionShim#execute(com.novell.nds.dirxml.driver.XmlDocument,
     *      com.novell.nds.dirxml.driver.XmlQueryProcessor)
     * @see SkeletonPublicationShim#start(com.novell.nds.dirxml.driver.XmlCommandProcessor)
     * @see #connect()
     */
    protected boolean connected;

    //~ Constructors -----------------------------------------------------------

    /**
     * Constructor.
     */
    protected CommonImpl()
    {
        trace            = null;
        driverRDN        = null;
        driverParams     = null;
        connected        = false;
    }//CommonImpl()

    //~ Methods ----------------------------------------------------------------

    /**
     * Sets this driver's initialization parameters.
     * 
     * <p></p>
     *
     * @param params this driver's initialization parameters; may be
     *        <code>null</code>
     */
    protected void setDriverParams(Map params)
    {
        driverParams = params;
    }//setDriverParams(Map):void

    /**
     * Gets this driver's initialization parameters.
     * 
     * <p></p>
     *
     * @return may be <code>null</code>
     */
    Map getDriverParams()
    {
        return this.driverParams;
    }//getDriverParams():Map

    /**
     * Sets this driver's name.
     * 
     * <p></p>
     *
     * @param name the Relative Distinguished Name (RDN) of this driver
     *        instance; may be <code>null</code>
     */
    protected void setDriverRDN(String name)
    {
        driverRDN = name;
    }//setDriverRDN(String):void

    /**
     * Gets this driver's name.
     * 
     * <p></p>
     *
     * @return will not return <code>null</code>
     */
    protected String getDriverRDN()
    {
        return (driverRDN == null) ? TRACE_ID
                                   : driverRDN;
    }//getDriverRDN():String

    /**
     * Creates a trace object.
     */
    protected void setTrace()
    {
        trace = new Trace(null);
    }//setTrace(String):void

    /**
     * Appends a populated <code>&lt;source&gt;</code> element to
     * <code>doc</code>.
     * 
     * <p></p>
     *
     * @param doc may be <code>null</code>
     */
    protected void appendSourceInfo(WriteableDocument doc)
    {
        if(doc != null)
        {
            XDSSourceElement  source;
            XDSProductElement product;

            source      = doc.appendSourceElement();
            product     = source.appendProductElement();

            //MODIFY:  put the time and date your driver was built here
            product.setBuild(XDS.BUILD);
            product.setInstance(driverRDN);

            //MODIFY:  put the marketing version of your driver here
            product.setVersion(XDS.VERSION);
            product.appendText(PRODUCT_NAME);
            source.appendContactElement(COMPANY_NAME);
        }//if
    }//appendSourceInfo(WriteableDocument):void

    /**
     * Utility method for instantiating an <code>XDSResultDocument</code>.
     * 
     * <p>
     * The returned result document contains a populated
     * <code>&lt;source&gt;</code> element.
     * </p>
     * 
     * <p></p>
     *
     * @return will not return <code>null</code>
     */
    protected XDSResultDocument newResultDoc()
    {
        XDSResultDocument resultDoc;

        resultDoc = new XDSResultDocument();
        appendSourceInfo(resultDoc);

        return resultDoc;
    }//newResultDoc():XDSResultDocument

    /**
     * Utility method for instantiating an <code>XDSCommandDocument</code>.
     * 
     * <p>
     * The returned result document contains a populated source element.
     * </p>
     * 
     * <p></p>
     *
     * @return will not return <code>null</code>
     */
    protected XDSCommandDocument newCommandDoc()
    {
        XDSCommandDocument commandDoc;

        commandDoc = new XDSCommandDocument();
        appendSourceInfo(commandDoc);

        return commandDoc;
    }//newCommandDoc():XDSCommandDocument

    /**
     * A non-interface method used to format trace values.
     *
     * @param string may be <code>null</code>
     *
     * @return a string enclosed in single quotes or <code>null</code>
     */
    protected static String toLiteral(String string)
    {
        return (string == null) ? null
                                : ("'" + string + "'");
    }//toLiteral(String):String

    /**
     * A non-interface method that connects a shim to the application if not
     * already connected or if the existing connection has been broken.
     * 
     * <p></p>
     *
     * @exception java.io.IOException if unable to connect
     */
    protected void connect()
        throws java.io.IOException
    {
        //MODIFY:  put code to connect to your application here
        trace.trace(
            "connect",
            1);

        if(!connected)
        {
            //do whatever is required to connect to the application
            //  e.g., open a Socket, etc.

            /*
               if (connection fails)
               {
                   throw new java.io.IOException("Can't connect to application");
               }
             */
            connected = true;
        }//if
    }//connect():void

    /**
     * A non-interface method that closes application connections.
     */
    protected void disconnect()
    {
        //MODIFY:  put code to disconnect from your application here
        trace.trace(
            "disconnect",
            1);

        connected = false;
    }//disconnect():void

    /**
     * Common <code>XmlQueryProcessor</code> implementation for the
     * SkeletonPublicationShim and SkeletonSubscriptionShim.
     * 
     * <p></p>
     *
     * @param query may be <code>null</code>
     * @param result unsued; present to ensure API consistency; may be
     *        <code>null</code>
     */
    protected void queryHandler(
        XDSQueryElement     query,
        QueryResultDocument result)
    {
        //example <query> element:

        /*
           <nds dtdversion="1.1" ndsversion="8.6">
               <source>
                   <product version="1.1a">DirXML</product>
                   <contact>Novell, Inc.</contact>
               </source>
               <input>
                   <query class-name="User" event-id="0">
                       <search-class class-name="User"/>
                       <search-attr attr-name="Surname">
                           <value timestamp="1040071990#3" type="string">a</value>
                       </search-attr>
                       <search-attr attr-name="Telephone Number">
                           <value timestamp="1040072034#1" type="teleNumber">222-2222</value>
                       </search-attr>
                       <read-attr/>
                   </query>
               </input>
           </nds>
         */

        //example query result:

        /*
           <nds dtdversion="1.1" ndsversion="8.6">
               <source>
                   <product build="20021216_0123" instance="Skeleton Driver (Java, XDS)" version="1.1">DirXML Skeleton Driver (Java, XDS)</product>
                   <contact>My Company Name</contact>
               </source>
               <output>
                   <status event-id="0" level="success" type="driver-general"/>
               </output>
           </nds>
         */
        trace.trace(
            "queryHandler",
            1);

        if(query == null)
        {
            //nothing to do
            return;
        }

        //The query can specify a read of a single object with one or more
        //attributes, or it can specify a search for an object of a particular
        //class, or various other things.  In a real driver, we would parse
        //the query contents and make appropriate application calls to execute
        //the query.  We would place the results of the query in zero or more
        //<instance> elements.
        trace.trace(
            "queryHandler: association      == " +
            toLiteral(query.extractAssociationText()));
        trace.trace(
            "queryHandler: class-name       == " +
            toLiteral(query.getClassName()));
        trace.trace(
            "queryHandler: dest-dn          == " +
            toLiteral(query.getDestDN()));
        trace.trace(
            "queryHandler: event-id         == " +
            toLiteral(query.getEventID()));
        trace.trace(
            "queryHandler: max-result-count == " + query.getMaxResultCount());
        trace.trace(
            "queryHandler: qualified-src-dn == " +
            toLiteral(query.getQualifiedSrcDN()));
        trace.trace(
            "queryHandler: scope            == " +
            toLiteral(query.getScope().toString()));
        trace.trace(
            "queryHandler: src-dn           == " + toLiteral(query.getSrcDN()));
        trace.trace(
            "queryHandler: src-entry-id     == " +
            toLiteral(query.getSrcEntryID()));

        List                  searchClasses;
        List                  searchAttrs;
        List                  readAttrs;
        ListIterator          l;
        XDSSearchClassElement sc;
        XDSSearchAttrElement  sa;
        XDSReadAttrElement    ra;

        searchClasses     = query.extractSearchClassElements();
        l                 = searchClasses.listIterator();

        while(l.hasNext())
        {
            sc = (XDSSearchClassElement)l.next();
            trace.trace(
                "queryHandler: search-class     == " +
                toLiteral(sc.getClassName()));
        }

        searchAttrs     = query.extractSearchAttrElements();
        l               = searchAttrs.listIterator();

        while(l.hasNext())
        {
            sa = (XDSSearchAttrElement)l.next();
            trace.trace(
                "queryHandler: search-attr      == " +
                toLiteral(sa.getAttrName()));
        }

        readAttrs     = query.extractReadAttrElements();
        l             = readAttrs.listIterator();

        while(l.hasNext())
        {
            ra = (XDSReadAttrElement)l.next();
            trace.trace(
                "queryHandler: read-attr        == " +
                toLiteral(ra.getAttrName()));
        }

        trace.trace(
            "queryHandler: contains query token?       " +
            query.containsQueryToken());
        trace.trace(
            "queryHandler: contains read attrs?        " +
            query.containsReadAttrElements());
        trace.trace(
            "queryHandler: contains search attrs?      " +
            query.containsSearchAttrElements());
        trace.trace(
            "queryHandler: contains search classes?    " +
            query.containsSearchClassElements());
        trace.trace(
            "queryHandler: has entry scope?            " +
            query.hasEntryScope());
        trace.trace(
            "queryHandler: has subordinates scope?     " +
            query.hasSubordinatesScope());
        trace.trace(
            "queryHandler: has subtree scope?          " +
            query.hasSubtreeScope());
        trace.trace(
            "queryHandler: has limited results?        " +
            query.hasLimitedResults());
        trace.trace(
            "queryHandler: has unlimited results?      " +
            query.hasUnlimitedResults());
        trace.trace(
            "queryHandler: has root base object?       " +
            query.hasRootBaseObject());
        trace.trace(
            "queryHandler: is cancelled query?         " + query.isCancelled());
        trace.trace(
            "queryHandler: is extended query?          " + query.isExtended());
        trace.trace(
            "queryHandler: is identity query?          " + query.isIdentity());
        trace.trace(
            "queryHandler: is initial query?           " +
            query.isInitialQuery());
        trace.trace(
            "queryHandler: is subsequent query?        " +
            query.isSubsequentQuery());
        trace.trace(
            "queryHandler: should read attrs?          " +
            query.shouldReadAttributes());
        trace.trace(
            "queryHandler: should read parent?         " +
            query.shouldReadParent());
        trace.trace(
            "queryHandler: should search all classes?  " +
            query.shouldSearchAllClasses());

        //since this is a skeleton, and there is nothing to query, just
        //return an empty result document with a success status; the
        //absence of an <instance> element tells the DirXML engine
        //that nothing matched the query.
    }//queryHandler(XDSQueryElement, QueryResultDocument):void
}//class CommonImpl
