/*
 * $Header: /home/cvspublic/jakarta-slide/src/share/org/apache/slide/common/NamespaceAccessTokenImpl.java,v 1.29 2004/12/15 16:26:51 masonjm Exp $
 * $Revision: 1.29 $
 * $Date: 2004/12/15 16:26:51 $
 *
 * ====================================================================
 *
 * Copyright 1999-2002 The Apache Software Foundation 
 *
 * 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.apache.slide.common;

import java.io.IOException;
import java.io.Reader;
import java.io.Writer;

import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;
import javax.transaction.TransactionManager;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.slide.content.Content;
import org.apache.slide.event.EventDispatcher;
import org.apache.slide.event.TransactionEvent;
import org.apache.slide.event.VetoException;
import org.apache.slide.lock.Lock;
import org.apache.slide.macro.Macro;
import org.apache.slide.search.Search;
import org.apache.slide.security.Security;
import org.apache.slide.structure.Structure;
import org.apache.slide.util.NamespaceConfigUtil;
import org.apache.slide.util.conf.Configuration;
import org.apache.slide.util.conf.ConfigurationElement;
import org.apache.slide.util.conf.ConfigurationException;
import org.apache.slide.util.conf.Populate;
import org.apache.slide.util.logger.Logger;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;


/**
 * Namespace access token implementation.
 *
 * @version $Revision: 1.29 $
 */
public final class NamespaceAccessTokenImpl implements NamespaceAccessToken {
    
    
    // ------------------------------------------------------------ Constructor
    
    /**
     * Constructor.
     *
     * @param namespace Namespace which can be accessed through this token
     */
    NamespaceAccessTokenImpl(Namespace namespace) {
        this.namespace = namespace;
        
        securityHelper = NamespaceConfigUtil.getSecurityImplementation(namespace);
        
        lockHelper = NamespaceConfigUtil.getLockImplementation(namespace, securityHelper);
        
        structureHelper = NamespaceConfigUtil.getStructureImplementation(
                namespace, securityHelper, lockHelper);
        
        contentHelper = NamespaceConfigUtil.getContentImplementation(
                namespace, securityHelper, structureHelper, lockHelper);
        
        searchHelper = NamespaceConfigUtil.getSearchImplementation(
                namespace, structureHelper, contentHelper);
        
        macroHelper = NamespaceConfigUtil.getMacroImplementation(
                namespace, securityHelper, contentHelper, structureHelper, lockHelper);
    }
    
    
    // ----------------------------------------------------- Instance Variables
    
    
    /**
     * Default namespace associated with this token.
     */
    Namespace namespace;
    
    
    /**
     * Structure helper functions.
     */
    private Structure structureHelper;
    
    
    /**
     * Content helper functions.
     */
    private Content contentHelper;
    
    
    /**
     * Lock helper functions.
     */
    private Lock lockHelper;
    
    
    /**
     * Search helper functions.
     */
    private Search searchHelper;
    
    
    /**
     * Security helper functions.
     */
    private Security securityHelper;
    
    
    /**
     * Macro helper functions.
     */
    private Macro macroHelper;
    
    
    // ------------------------------------------------------------- Properties
    
    
    /**
     * Get the structure helper.
     *
     * @return Structure helper
     */
    public Structure getStructureHelper() {
        return structureHelper;
    }
    
    
    /**
     * Get the content helper.
     *
     * @return Content helper
     */
    public Content getContentHelper() {
        return contentHelper;
    }
    
    
    /**
     * Get the lock helper.
     *
     * @return Lock Lock helper
     */
    public Lock getLockHelper() {
        return lockHelper;
    }
    
    
    /**
     * Get the search helper.
     *
     * @return Search Search helper
     */
    public Search getSearchHelper() {
        return searchHelper;
    }
    
    
    /**
     * Get the security helper.
     *
     * @return Security Security helper
     */
    public Security getSecurityHelper() {
        return securityHelper;
    }
    
    
    /**
     * Get the macro helper.
     *
     * @return Macro Macro helper
     */
    public Macro getMacroHelper() {
        return macroHelper;
    }
    
    
    /**
     * Retrive the namespace configuration.
     *
     * @return NamespaceConfig Namespace configuration
     */
    public NamespaceConfig getNamespaceConfig() {
        return namespace.getConfig();
    }
    
    
    /**
     * Get namespace logger.
     *
     * @return The logger associated with the namespace.
     */
    public Logger getLogger() {
        return namespace.getApplicationLogger();
    }
    
    
    // ------------------------------------------- NamespaceAccessToken Methods
    
    
    /**
     * Import data from Avalon configuration object.
     *
     * @param token SlideToken, used for access to the namespace
     * @param dataConfiguration Configuration object
     * @exception ConfigurationException Something went wrong during the
     * reading of the XML
     * @exception UnknownObjectClassException Object class not found
     * @exception ServiceAccessException Error accessing service
     */
    public void importData(SlideToken token, Configuration dataConfiguration)
        throws ConfigurationException, UnknownObjectClassException,
        ServiceAccessException {
        
        XMLUnmarshaller.unmarshal(this, token, dataConfiguration);
        
    }
    
    
    /**
     * Import data from reader.
     *
     * @param token SlideToken, used for access to the namespace
     * @param reader Reader
     * @exception ConfigurationException Something went wrong during the
     * reading of the XML
     * @exception UnknownObjectClassException Object class not found
     * @exception ServiceAccessException Error accessing service
     */
    public void importData(SlideToken token, Reader reader)
        throws ConfigurationException, UnknownObjectClassException,
        ServiceAccessException, SAXException, IOException {
        
        try {
            
            SAXParserFactory factory = SAXParserFactory.newInstance();
            factory.setNamespaceAware(false);
            factory.setValidating(false);
            SAXParser parser = factory.newSAXParser();
            
            Populate pop = new Populate();
            Configuration configuration = new ConfigurationElement
                (pop.load(new InputSource(reader), parser.getXMLReader()));
            
            importData(token, configuration);
            
        } catch (javax.xml.parsers.FactoryConfigurationError e) {
            throw new SlideRuntimeException(e.getMessage());
        } catch (javax.xml.parsers.ParserConfigurationException e) {
            throw new SlideRuntimeException(e.getMessage());
        }/* catch (Exception e) {
         throw new ConfigurationException(e.getMessage());
         }*/
        
    }
    
    
    /**
     * Saves Slide Data to XML.
     *
     * @param writer Writer
     * @exception SlideException
     */
    public void exportData(SlideToken token, Writer writer)
        throws SlideException {
        exportData(token, writer, "/");
    }
    
    
    /**
     * Saves Slide Data to XML.
     *
     * @param writer Writer
     * @param startNode Start generating XML from this node of the Slide tree
     * @exception SlideException
     */
    public void exportData(SlideToken token, Writer writer,
                           String startNode)
        throws SlideException {
        
        XMLMarshaller.marshal(this, token, writer, startNode);
        
    }
    
    
    /**
     * Disconnect.
     */
    public void disconnect() {
        try {
            namespace.disconnectServices();
        } catch(SlideException e) {
            e.printStackTrace();
        }
    }
    
    
    /**
     * Get namespace name.
     *
     * @return String namespace name.
     */
    public String getName() {
        return namespace.getName();
    }
    
    /**
     * Builds a new uri object to access this namespace.
     *
     * @param token SlideToken
     * @param uri Requested Uri
     * @return Uri
     */
    public Uri getUri(SlideToken token, String uri) {
        return namespace.getUri(token, uri);
    }
    
    
    // ------------------------------------------------ UserTransaction Methods
    
    
    /**
     * Create a new transaction and associate it with the current thread.
     *
     * @exception NotSupportedException Thrown if the thread is already
     * associated with a transaction and the Transaction Manager
     * implementation does not support nested transactions.
     * @exception SystemException Thrown if the transaction manager encounters
     * an unexpected error condition.
     */
    public void begin()
        throws NotSupportedException, SystemException {
        if ( TransactionEvent.BEGIN.isEnabled() ) EventDispatcher.getInstance().fireEvent(TransactionEvent.BEGIN, new TransactionEvent(this));
        namespace.getTransactionManager().begin();
    }
    
    
    /**
     * Complete the transaction associated with the current thread. When this
     * method completes, the thread becomes associated with no transaction.
     *
     * @exception RollbackException Thrown to indicate that the transaction
     * has been rolled back rather than committed.
     * @exception HeuristicMixedException Thrown to indicate that a heuristic
     * decision was made and that some relevant updates have been committed
     * while others have been rolled back.
     * @exception HeuristicRollbackException Thrown to indicate that a
     * heuristic decision was made and that some relevant updates have been
     * rolled back.
     * @exception SecurityException Thrown to indicate that the thread is not
     * allowed to commit the transaction.
     * @exception IllegalStateException Thrown if the current thread is not
     * associated with a transaction.
     * @exception SystemException Thrown if the transaction manager encounters
     * an unexpected error condition.
     */
    public void commit()
        throws RollbackException, HeuristicMixedException,
        HeuristicRollbackException, SecurityException, IllegalStateException,
        SystemException {
        try {
            if ( TransactionEvent.COMMIT.isEnabled() ) EventDispatcher.getInstance().fireVetoableEvent(TransactionEvent.COMMIT, new TransactionEvent(this));
        } catch ( VetoException e ) {
            throw new SystemException(e.getMessage());
        }
        namespace.getTransactionManager().commit();
        if ( TransactionEvent.COMMITED.isEnabled() ) EventDispatcher.getInstance().fireEvent(TransactionEvent.COMMITED, new TransactionEvent(this));
    }
    
    
    /**
     * Roll back the transaction associated with the current thread. When
     * this method completes, the thread becomes associated with no
     * transaction.
     *
     * @exception SecurityException Thrown to indicate that the thread is not
     * allowed to commit the transaction.
     * @exception IllegalStateException Thrown if the current thread is not
     * associated with a transaction.
     * @exception SystemException Thrown if the transaction manager encounters
     * an unexpected error condition.
     */
    public void rollback()
        throws SecurityException, IllegalStateException, SystemException {
        if ( TransactionEvent.ROLLBACK.isEnabled() ) EventDispatcher.getInstance().fireEvent(TransactionEvent.ROLLBACK, new TransactionEvent(this));
        namespace.getTransactionManager().rollback();
    }
    
    
    /**
     * Modify the transaction associated with the current thread such that
     * the only possible outcome of the transaction is to roll back the
     * transaction.
     *
     * @exception IllegalStateException Thrown if the current thread is not
     * associated with a transaction.
     * @exception SystemException Thrown if the transaction manager encounters
     * an unexpected error condition.
     */
    public void setRollbackOnly()
        throws IllegalStateException, SystemException {
        namespace.getTransactionManager().setRollbackOnly();
    }
    
    
    /**
     * Obtain the status of the transaction associated with the current thread.
     *
     * @exception SystemException Thrown if the transaction manager encounters
     * an unexpected error condition.
     * @return The transaction status. If no transaction is associated with
     * the current thread, this method returns the Status.NoTransaction value.
     */
    public int getStatus()
        throws SystemException {
        return namespace.getTransactionManager().getStatus();
    }
    
    
    /**
     * Modify the value of the timeout value that is associated with the
     * transactions started by the current thread with the begin method.
     * <p>
     * If an application has not called this method, the transaction service
     * uses some default value for the transaction timeout.
     *
     * @param seconds The value of the timeout in seconds. If the value is
     * zero, the transaction service restores the default value.
     * @exception SystemException Thrown if the transaction manager encounters
     * an unexpected error condition.
     */
    public void setTransactionTimeout(int seconds)
        throws SystemException {
        namespace.getTransactionManager().setTransactionTimeout(seconds);
    }
    
    public TransactionManager getTransactionManager() {
        return namespace.getTransactionManager();
    }
    
}


