/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/urm/org/apache/slide/urm/common/URMInit.java,v 1.5 2005/03/02 10:53:35 eckehard Exp $
 * $Revision: 1.5 $
 * $Date: 2005/03/02 10:53:35 $
 *
 * ====================================================================
 *
 * Copyright 1999-2004 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.urm.common;
import com.softwareag.tamino.db.api.accessor.*;

import com.softwareag.tamino.db.api.common.TAccessFailureException;
import com.softwareag.tamino.db.api.common.TException;
import com.softwareag.tamino.db.api.connection.TConnection;
import com.softwareag.tamino.db.api.connection.TConnectionFactory;
import com.softwareag.tamino.db.api.connection.TIsolationDegree;
import com.softwareag.tamino.db.api.connection.TLocalTransaction;
import com.softwareag.tamino.db.api.connection.TServerNotAvailableException;
import com.softwareag.tamino.db.api.objectModel.TXMLObject;
import com.softwareag.tamino.db.api.objectModel.dom.TDOMObjectModel;
import com.softwareag.tamino.db.api.objectModel.jdom.TJDOMObjectModel;
import com.softwareag.tamino.db.api.response.TResponse;
import org.apache.slide.urm.URMException;
import org.apache.slide.urm.common.impl.URMConfiguratorUtil;
import org.apache.slide.urm.common.impl.URMConfiguratorXML;
import org.apache.slide.urm.utils.messagelogger.MessageLogger;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Text;
import org.jdom.input.SAXBuilder;
import org.jdom.output.DOMOutputter;
import org.xml.sax.InputSource;
import com.softwareag.tamino.db.api.objectModel.TXMLObjectIterator;
import java.util.HashSet;
import org.w3c.dom.Node;
import org.w3c.dom.NamedNodeMap;

/**
 * @author eckehard.hermann@softwareag.com
 * @author dieter.kessler@softwareag.com
 * @author zsolt.sasvarie@softwareag.com
 */

public class URMInit
{
    private static final String NAME = "name";
    private static final String ANNOTATION_TAG = "annotation";
    private static final String APPINFO_TAG = "appinfo";
    private static final String SCHEMAINFO_TAG = "schemaInfo";
    private static final String ELEMENTINFO_TAG = "elementInfo";
    private static final String PHYSICAL_TAG = "physical";
    private static final String NATIVE_TAG = "native";
    private static final String OBJECTREF_TAG = "objectRef";
    private static final String COLLECTIONREF_TAG = "collectionRef";
    private static final String COMPLEXTYPE_TAG = "complexType";
    private static final String SEQUENCE_TAG = "sequence";
    private static final String COLLECTION_TAG = "collection";
    private static final String ELEMENT_TAG = "element";
    private static final String NAME_ATTR = "name";
    private static final String ROLE = "Role";
    private static final String USERROLEMAPPING = "UserRoleMapping";
    private static final String URMROLES = "UserRoleMapping";
    private static final String USERNAME = "UserName";
    private static final String DOMAIN = "Domain";
    private static final String INO_SECURITY_COLLECTION = "ino:security";
    private static final String WRITE_ACL = "write_access_acl";
    private static final String NO_ACL = "no_access_acl";
    private static final String WRITE_GROUP_NAME = "urm_admins";
    private static String defaultSchemaVersion = "<?xml version=\"1.0\"?>";
    private static String TAMINO_TSD_3_NAMESPACE_URI = "http://namespaces.softwareag.com/tamino/response2";
    
    private static org.apache.log4j.Logger msLogger =
        org.apache.log4j.Logger.getLogger(URMInit.class.getName());
    
    private TXMLObjectAccessor xmlObjectAccessor;
    
    private TLocalTransaction taminoTransaction;

    public static void init(boolean enableSecurity, String admin, String domain) throws URMException {
        URMInit init = new URMInit();
        init.initURM(enableSecurity, admin, domain);
    }
    
    private static InputStream getResourceStream(String name) throws URMException {
        InputStream in =URMInit.class.getResourceAsStream(name);
        if (in == null) {
            throw new URMException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0051", name));
        } else {
            return in;
        }
    }
    
    boolean result = true;
    String url = null;
    String collection = null;
    String userMetaDataSchemaName = null;
    TXMLObject userMetadataSchema = null;
    String userRoleMappingSchemaName = null;
    TXMLObject userRoleMappingSchema = null;
    String roleMetaDataSchemaName = null;
    TXMLObject roleMetaDataSchema = null;
    String actionMetaDataSchemaName = null;
    TXMLObject actionMetaDataSchema = null;
    String aclMetaDataSchemaName = null;
    TXMLObject aclMetaDataSchema = null;
    String metaDataUserDomain = null;
    String metaDataUserName = null;
    String metaDataUserPassword = null;
    TConnection tConnection = null;
    String urmRoot = null;
    String urmAdmin = null;
    String urmGuest = null;
    String urmInitAdmin = null;
    String allAction = "ALLAction";
    
    public boolean initURM(boolean enableSecurity, String admin, String domain) throws URMException{
        try {

            // get UserMetaData DB info from config file
            URMConfigurator config = URMConfiguratorXML.newConfigfileConfigurator();
            
            // get DB info from config file
            URMConfigurator adminConfig = config.getSubConfigurator("/Authenticator/Administrator");
            Iterator dbAttrs = URMConfiguratorUtil.getAttributeList(adminConfig, msLogger);
            while (dbAttrs != null && dbAttrs.hasNext()) {
                URMConfigurator dbattrconf = ((URMConfigurator)dbAttrs.next());
                Properties dbattr = dbattrconf.getProperties();
                if (dbattr == null)
                    continue;
                String aclattrname = (String)dbattr.get("name");
                if (aclattrname == null)
                    continue;
                if (aclattrname.equals("databaseUri"))
                    url = (String)dbattr.get("value");
                else if (aclattrname.equals("collectionName")) {
                    collection = (String)dbattr.get("value");
                } else if (aclattrname.equals("databaseAccount")) {
                    metaDataUserName = (String)dbattr.get("value");
                } else if (aclattrname.equals("databasePassword")) {
                    metaDataUserPassword = (String)dbattr.get("value");
                } else if (aclattrname.equals("databaseDomain")) {
                    metaDataUserDomain = (String)dbattr.get("value");
                } else if (aclattrname.equals("initSecurity")) {
                    if (!enableSecurity) enableSecurity = (new Boolean((String)dbattr.get("value"))).booleanValue();
                } else if (aclattrname.equals("userMetaDataSchemaName")) {
                    userMetaDataSchemaName = (String)dbattr.get("value");
                } else if (aclattrname.equals("userRoleMappingSchemaName")) {
                    userRoleMappingSchemaName = (String)dbattr.get("value");
                } else if (aclattrname.equals("urmInitAdmin")) {
                    urmInitAdmin = (String)dbattr.get("value");
                }
            }
            
            // get RoleData DB info from config file
            URMConfigurator roleConfig = config.getSubConfigurator("/Authenticator/Administrator/RoleManager");
            Iterator roleAttrs = URMConfiguratorUtil.getAttributeList(roleConfig, msLogger);
            while (roleAttrs != null && roleAttrs.hasNext()) {
                URMConfigurator roleattrconf = ((URMConfigurator)roleAttrs.next());
                Properties roleattr = roleattrconf.getProperties();
                if (roleattr == null)
                    continue;
                String roleattrname = (String)roleattr.get("name");
                if (roleattrname == null)
                    continue;
                if (roleattrname.equals("roleMetaDataSchemaName")) {
                    roleMetaDataSchemaName = (String)roleattr.get("value");
                } else if (roleattrname.equals("urmRoot")) {
                    urmRoot = (String)roleattr.get("value");
                } else if (roleattrname.equals("urmAdmin")) {
                    urmAdmin = (String)roleattr.get("value");
                } else if (roleattrname.equals("urmGuest")) {
                    urmGuest = (String)roleattr.get("value");
                }
            }
            
            // get RoleData DB info from config file
            URMConfigurator aclConfig = config.getSubConfigurator("/Authenticator/Administrator/AclAdministrator");
            Iterator aclAttrs = URMConfiguratorUtil.getAttributeList(aclConfig, msLogger);
            while (aclAttrs != null && aclAttrs.hasNext()) {
                URMConfigurator aclattrconf = ((URMConfigurator)aclAttrs.next());
                Properties aclattr = aclattrconf.getProperties();
                if (aclattr == null)
                    continue;
                String aclattrname = (String)aclattr.get("name");
                if (aclattrname == null)
                    continue;
                if (aclattrname.equals("actionMetaDataSchemaName")) {
                    actionMetaDataSchemaName = (String)aclattr.get("value");
                } else if (aclattrname.equals("aclMetaDataSchemaName")) {
                    aclMetaDataSchemaName = (String)aclattr.get("value");
                }
            }

            // return if important settings are missing
            if (url == null) throw new URMException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0054", "databaseUri"));
            if (collection == null) throw new URMException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0054", "collectionName"));
            if (userMetaDataSchemaName == null) throw new URMException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0054", "userMetaDataSchemaName"));
            if (userRoleMappingSchemaName == null) throw new URMException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0054", "userRoleMappingSchemaName"));
            if (roleMetaDataSchemaName == null) throw new URMException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0054", "roleMetaDataSchemaName"));
            if (actionMetaDataSchemaName == null) throw new URMException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0054", "actionMetaDataSchemaName"));
            if (aclMetaDataSchemaName == null) throw new URMException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0054", "aclMetaDataSchemaName"));
                                        
            userMetadataSchema = getXMLSchema(collection,"/" + userMetaDataSchemaName + ".TSD");
            userRoleMappingSchema = getUserRoleXMLSchema(collection,"/" + userRoleMappingSchemaName + ".TSD");
            roleMetaDataSchema = getXMLSchema(collection,"/" + roleMetaDataSchemaName + ".TSD");
            actionMetaDataSchema = getXMLSchema(collection,"/" + actionMetaDataSchemaName + ".TSD");
            aclMetaDataSchema = getXMLSchema(collection,"/" + aclMetaDataSchemaName + ".TSD");
            
            // get Tamino Connection
            tConnection = getConnection (url, metaDataUserDomain, metaDataUserName, metaDataUserPassword);
            TSchemaDefinition3Accessor schema3Accessor = null;
            schema3Accessor = tConnection.newSchemaDefinition3Accessor(TJDOMObjectModel.getInstance());

            // return if a schema file has not been found
            if ((userMetadataSchema == null) || (roleMetaDataSchema == null) || (actionMetaDataSchema == null) || (aclMetaDataSchema == null) || (userRoleMappingSchema == null)) return false;
//            try {
                 schema3Accessor.define(userMetadataSchema);
//            } catch (Exception e) {}
//            try {
                 schema3Accessor.define(roleMetaDataSchema);
//            } catch (Exception e) {}
//            try {
                 schema3Accessor.define(actionMetaDataSchema);
//            } catch (Exception e) {}
//            try {
                schema3Accessor.define(aclMetaDataSchema);
//            } catch (Exception e) {}
//            try {
                schema3Accessor.define(userRoleMappingSchema);
//            } catch (Exception e) {
//            }
            
            // insert init data
            TXMLObjectAccessor accessor  = tConnection.newXMLObjectAccessor(TAccessLocation.newInstance(collection), TJDOMObjectModel.getInstance());

//            try {
                if (!existRole(accessor, URMConstants.URM_ROOT_ROLE))
                    accessor.insert(getXMLObject(collection, urmRoot + ".xml"));
//            } catch (Exception e) {
//            }
//            try {
                if (!existRole(accessor, URMConstants.URM_ADMIN_ROLE)){
                    accessor.insert(getXMLObject(collection, urmAdmin + ".xml"));
                    TXMLObject adminObj = getXMLAdminObject(admin, domain, collection, urmInitAdmin + ".xml");
                    accessor.insert(adminObj);
                }
//            } catch (Exception e) {
//            }
//            try {
                if (!existRole(accessor, URMConstants.URM_GUEST_ROLE)) accessor.insert(getXMLObject(collection, urmGuest + ".xml"));
//            } catch (Exception e) {
//            }
            try {
                if (createAdminRoleMapping(admin, domain, URMConstants.URM_ADMIN_ROLE, tConnection, collection)) {
                    TXMLObject adminObj = getXMLAdminObject(admin, domain, collection, urmInitAdmin + ".xml");
                    accessor.insert(adminObj);
                }
            } catch (URMInternalServerException e) {
                if (enableSecurity) createTaminoSecurity(collection, url, metaDataUserDomain, metaDataUserName, metaDataUserPassword);
                tConnection.close();
                throw e;
            }
            tConnection.close();
            if (enableSecurity) createTaminoSecurity(collection, url, metaDataUserDomain, metaDataUserName, metaDataUserPassword);
//            else deleteTaminoSecurity(collection, url, metaDataUserDomain, metaDataUserName, metaDataUserPassword);
            return result;
        } catch (Exception e) {
            try{
                tConnection.close();
            }catch(Exception ec){}
            e.printStackTrace();
            throw new URMException(msLogger, "E", e);
        }
    }
    
    private TConnection getConnection(String mDatabaseUri, String domain, String userId, String password)
            throws URMConnectionException {
        TConnection conn = null;
        try {
            TConnectionFactory cf = TConnectionFactory.getInstance();
            if (domain == null)
                conn = cf.newConnection(mDatabaseUri, userId, password);
            else
                conn = cf.newConnection(mDatabaseUri, domain, userId, password);
        } catch (TServerNotAvailableException  ex) {
            TException de = ex.getDeepestTException();
            if (de == null)
                de = ex;
            throw new URMConnectionException(MessageLogger.getAndLogMessage(msLogger, "F", de));
        }
        conn.setIsolationDegree(TIsolationDegree.STABLE_DOCUMENT);
        
        return conn;
    }
    
    /**
     ** Create an XML content schema for the given collection and doctype using a specific schemaVersion.
     **
     ** @pre        true
     ** @post       true
     **
     ** @param      collection the Tamino collection
     ** @param      templateLocation The (physical) location of the template
     ** @return     a new schema
     **
     ** @exception  XException
     **/
    public static TXMLObject getXMLSchema (String collection, String templateLocation) throws URMException
    {

        TXMLObject result = null;
        
        try {
            // get the template
            InputStream in;
            in = getResourceStream (templateLocation);
            
            // parse the template
            SAXBuilder sax = new SAXBuilder();
            Document template = sax.build( in );
            result = adoptTSDtemplate (template, collection);
            
        }
        catch (IOException e) {
            throw new URMException(msLogger, "E", e);
        }
        catch (JDOMException e) {
            throw new URMException(msLogger, "E", e);
        }
        // TEST ONLY
        // print the schema
        //try { new XMLOutputter().output (new org.jdom.input.DOMBuilder().build((org.w3c.dom.Element )result.getElement()), System.out);}
        //catch (java.io.IOException printException) {printException.printStackTrace();}
        // TEST ONLY
        return result;
    }
    
        /**
     ** Create an XML content schema for the given collection and doctype using a specific schemaVersion.
     **
     ** @pre        true
     ** @post       true
     **
     ** @param      collection the Tamino collection
     ** @param      templateLocation The (physical) location of the template
     ** @return     a new schema
     **
     ** @exception  XException
     **/
    public static TXMLObject getUserRoleXMLSchema (String collection, String templateLocation) throws URMException
    {

        TXMLObject result = null;
        
        try {
            // get the template
            InputStream in;
            in = getResourceStream (templateLocation);
            
            // parse the template
            SAXBuilder sax = new SAXBuilder();
            Document template = sax.build( in );
            result = adoptUserRoleTSDtemplate (template, collection);
            
        }
        catch (IOException e) {
            throw new URMException(msLogger, "E", e);
        }
        catch (JDOMException e) {
            throw new URMException(msLogger, "E", e);
        }
        // TEST ONLY
        // print the schema
        //try { new XMLOutputter().output (new org.jdom.input.DOMBuilder().build((org.w3c.dom.Element )result.getElement()), System.out);}
        //catch (java.io.IOException printException) {printException.printStackTrace();}
        // TEST ONLY
        return result;
    }
   
    /**
     ** Create an XML content schema for the given collection and doctype using a specific schemaVersion.
     **
     ** @pre        true
     ** @post       true
     **
     ** @param      collection the Tamino collection
     ** @param      templateLocation The (physical) location of the template
     ** @return     a new schema
     **
     ** @exception  XException
     **/
    public static TXMLObject getXMLObject (String collection, String templateLocation) throws URMException
    {

        TXMLObject result = null;
        
        try {
            // get the template
            InputStream in;
            in = getResourceStream ("/" + templateLocation);
            
            // parse the template
            SAXBuilder sax = new SAXBuilder();
            Document template = sax.build( in );
            result = TXMLObject.newInstance(new DOMOutputter().output(template));
            result.setCollection(collection);
        }
        catch (IOException e) {
            throw new URMException(msLogger, "E", e);
        }
        catch (JDOMException e) {
            throw new URMException(msLogger, "E", e);
        }
        // TEST ONLY
        // print the schema
        //try { new XMLOutputter().output (new org.jdom.input.DOMBuilder().build((org.w3c.dom.Element )result.getElement()), System.out);}
        //catch (java.io.IOException printException) {printException.printStackTrace();}
        // TEST ONLY
        return result;
    }
    
        /**
     ** Create an XML content schema for the given collection and doctype using a specific schemaVersion.
     **
     ** @pre        true
     ** @post       true
     **
     ** @param      collection the Tamino collection
     ** @param      templateLocation The (physical) location of the template
     ** @return     a new schema
     **
     ** @exception  XException
     **/
    public static TXMLObject getXMLAdminObject (String admin, String domain, String collection, String templateLocation) throws URMException
    {

        TXMLObject result = null;
        
        try {
            // get the template
            InputStream in;
            in = getResourceStream ("/" + templateLocation);
            
            // parse the template
            SAXBuilder sax = new SAXBuilder();
            Document template = sax.build( in );
            Element elem = template.getRootElement();
            List children = elem.getChildren();
            Iterator childIter = children.iterator();
            if (admin != null) {
                while (childIter.hasNext()) {
                    Element currentChild = (Element) childIter.next();
                    if (currentChild.getName().equals(USERNAME)) {
                        currentChild.setText(admin);
                        currentChild.removeAttribute(DOMAIN);
                        if (domain != null) {
                            currentChild.setAttribute(DOMAIN, domain);
                        }
                    }
                }
            }
            result = TXMLObject.newInstance(new DOMOutputter().output(template));
            result.setCollection(collection);
            
        }
        catch (IOException e) {
            throw new URMException(msLogger, "E", e);
        }
        catch (JDOMException e) {
            throw new URMException(msLogger, "E", e);
        }
        // TEST ONLY
        // print the schema
        //try { new XMLOutputter().output (new org.jdom.input.DOMBuilder().build((org.w3c.dom.Element )result.getElement()), System.out);}
        //catch (java.io.IOException printException) {printException.printStackTrace();}
        // TEST ONLY
        return result;
    }
    
    /**
     ** Replace the tokens for collection name, schema name, doctype name
     ** in the given TSD3 template
     **
     ** @pre        (template != null)
     ** @pre        (collection != null)
     ** @pre        (doctype != null)
     **
     ** @param      template     template of a TSD3 schema/doctype
     ** @param      collection   collection name of the schema
     ** @param      doctype      doctype name
     **
     ** @return     schema/doctype definition
     **
     ** @exception  JDOMException
     **
     */
    private static TXMLObject adoptTSDtemplate (Document template,
                                                 String collection)
        throws JDOMException   {
   
        TXMLObject result = null;
        
        Element schemaElem = template.getRootElement();
     
        List schemaChildList = schemaElem.getChildren();
        Iterator it3 = schemaChildList.iterator();
        while (it3.hasNext()) {
            Element annotElem = (Element)it3.next();
            
            if (annotElem.getName().equals(ANNOTATION_TAG)) {
                List annotationChildList = annotElem.getChildren();
                Iterator it4 = annotationChildList.iterator();
                while (it4.hasNext()) {
                    Element appInfoElem = (Element)it4.next();
                    
                    if (appInfoElem.getName().equals(APPINFO_TAG)) {
                        List appInfoChildList = appInfoElem.getChildren();
                        Iterator it = appInfoChildList.iterator();
                        while (it.hasNext()) {
                            Element schemaInfoElem = (Element)it.next();
                            String name = schemaInfoElem.getName();
                            if (name.equals(SCHEMAINFO_TAG)) {
                                
                                List schemaInfoList = schemaInfoElem.getChildren();
                                Iterator it2 = schemaInfoList.iterator();
                                while (it2.hasNext()) {
                                    Element elem2 = (Element)it2.next();
                                    String name2 = elem2.getName();
                                    if (name2.equals(COLLECTION_TAG)) {
                                        // set schema name:
                                        elem2.removeAttribute( NAME );
                                        elem2.setAttribute( new Attribute(NAME, collection ) );
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
         
        // create schema instance
        result = TXMLObject.newInstance(new DOMOutputter().output(template));
        return result;
    }
    
        /**
     ** Replace the tokens for collection name, schema name, doctype name
     ** in the given TSD3 template
     **
     ** @pre        (template != null)
     ** @pre        (collection != null)
     ** @pre        (doctype != null)
     **
     ** @param      template     template of a TSD3 schema/doctype
     ** @param      collection   collection name of the schema
     ** @param      doctype      doctype name
     **
     ** @return     schema/doctype definition
     **
     ** @exception  JDOMException
     **
     */
    private static TXMLObject adoptUserRoleTSDtemplate (Document template,
                                                 String collection)
        throws JDOMException   {
   
        TXMLObject result = null;
        
        Element schemaElem = template.getRootElement();
     
        List schemaChildList = schemaElem.getChildren();
        Iterator it3 = schemaChildList.iterator();
        while (it3.hasNext()) {
            Element annotElem = (Element)it3.next();
            
            if (annotElem.getName().equals(ANNOTATION_TAG)) {
                List annotationChildList = annotElem.getChildren();
                Iterator it4 = annotationChildList.iterator();
                while (it4.hasNext()) {
                    Element appInfoElem = (Element)it4.next();
                    
                    if (appInfoElem.getName().equals(APPINFO_TAG)) {
                        List appInfoChildList = appInfoElem.getChildren();
                        Iterator it = appInfoChildList.iterator();
                        while (it.hasNext()) {
                            Element schemaInfoElem = (Element)it.next();
                            String name = schemaInfoElem.getName();
                            if (name.equals(SCHEMAINFO_TAG)) {
                                
                                List schemaInfoList = schemaInfoElem.getChildren();
                                Iterator it2 = schemaInfoList.iterator();
                                while (it2.hasNext()) {
                                    Element elem2 = (Element)it2.next();
                                    String name2 = elem2.getName();
                                    if (name2.equals(COLLECTION_TAG)) {
                                        // set schema name:
                                        elem2.removeAttribute( NAME );
                                        elem2.setAttribute( new Attribute(NAME, collection ) );
                                    }
                                }
                            }
                        }
                    }
                }
            } else if (annotElem.getName().equals(ELEMENT_TAG)) {
                if ((annotElem.getAttributeValue(NAME_ATTR).equals(USERROLEMAPPING))) {
                    List annotationChildList = annotElem.getChildren();
                    Iterator it41 = annotationChildList.iterator();
                    while (it41.hasNext()) {
                        Element annotElem12 = (Element)it41.next();
                        if (annotElem12.getName().equals(COMPLEXTYPE_TAG)) {
                            List annotation12ChildList = annotElem12.getChildren();
                            Iterator it12 = annotation12ChildList.iterator();
                            while (it12.hasNext()) {
                                Element annotElem13 = (Element)it12.next();
                                if (annotElem13.getName().equals(SEQUENCE_TAG)) {
                                    List annotation13ChildList = annotElem13.getChildren();
                                    Iterator it13 = annotation13ChildList.iterator();
                                    while (it13.hasNext()) {
                                        Element annotElem11 = (Element)it13.next();
                                        if (annotElem11.getName().equals(ELEMENT_TAG) && (annotElem11.getAttributeValue(NAME_ATTR).equals(ROLE))) {
                                            List annotation11ChildList = annotElem11.getChildren();
                                            Iterator it4 = annotation11ChildList.iterator();
                                            while (it4.hasNext()) {
                                                Element annotElem1 = (Element)it4.next();
                                                if (annotElem1.getName().equals(ANNOTATION_TAG)) {
                                                    List annotation1ChildList = annotElem1.getChildren();
                                                    Iterator it5 = annotation1ChildList.iterator();
                                                    while (it5.hasNext()) {
                                                        Element appInfoElem = (Element)it5.next();
                                                        if (appInfoElem.getName().equals(APPINFO_TAG)) {
                                                            List appInfoChildList = appInfoElem.getChildren();
                                                            Iterator it = appInfoChildList.iterator();
                                                            while (it.hasNext()) {
                                                                Element elmInfoElem = (Element)it.next();
                                                                String name = elmInfoElem.getName();
                                                                if (name.equals(ELEMENTINFO_TAG)) {
                                                                    List elmInfoList = elmInfoElem.getChildren();
                                                                    Iterator it2 = elmInfoList.iterator();
                                                                    while (it2.hasNext()) {
                                                                        Element elem2 = (Element)it2.next();
                                                                        String name2 = elem2.getName();
                                                                        if (name2.equals(PHYSICAL_TAG)) {
                                                                            List phyList = elem2.getChildren();
                                                                            Iterator it21 = phyList.iterator();
                                                                            while (it21.hasNext()) {
                                                                                Element elem22 = (Element)it21.next();
                                                                                String name22 = elem22.getName();
                                                                                if (name22.equals(NATIVE_TAG)) {
                                                                                    List elem22List = elem22.getChildren();
                                                                                    Iterator it22 = elem22List.iterator();
                                                                                    while (it22.hasNext()) {
                                                                                        Element elem23 = (Element)it22.next();
                                                                                        String name23 = elem23.getName();
                                                                                        if (name23.equals(OBJECTREF_TAG)) {
                                                                                            List elem23List = elem23.getChildren();
                                                                                            Iterator it23 = elem23List.iterator();
                                                                                            while (it23.hasNext()) {
                                                                                                Element elem24 = (Element)it23.next();
                                                                                                String name24 = elem24.getName();
                                                                                                if (name24.equals(COLLECTIONREF_TAG)){
                                                                                                    List content = elem24.getContent();
                                                                                                    Iterator contentIter  = content.iterator();
                                                                                                    Text conElm = (Text) contentIter.next();
                                                                                                    conElm.setText(collection);
                                                                                                    
                                                                                                }
                                                                                            }
                                                                                        }
                                                                                    }
                                                                                }
                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
         
        // create schema instance
        result = TXMLObject.newInstance(new DOMOutputter().output(template));
        return result;
    }
    
    /**
     * Method createSchema
     *
     * @param    taminoCollection    a  String
     * @param    schema              a  TXMLObject
     *
     * @throws   TException
     *
     */
    private void createSchema(TConnection tConnection, String taminoCollection, TXMLObject schema ) throws URMException {
        try {
            TSchemaDefinition3Accessor schema3Accessor = null;
            schema3Accessor = tConnection.newSchemaDefinition3Accessor(TJDOMObjectModel.getInstance());
            schema3Accessor.define( schema );
        }
        catch (TException e) {
            throw new URMException(
                "Could not create schema (docname="+schema.getDocname()+", doctype="+schema.getDoctype()+", id="+schema.getId()+
                    ") in collection "+taminoCollection, e );
        }

    }
    
    private boolean existRole(TXMLObjectAccessor mObjectAccessor, String role) {
    
        TXQuery query = TXQuery.newInstance("for    $b in input()/Role " +
                                            "where  $b/RoleName = '" + role + "' " +
                                            "return $b/RoleName");
        try {
            TResponse response = mObjectAccessor.xquery(query);
            TXMLObject tobj = response.getFirstXMLObject();
            Object obj_el = tobj != null ? tobj.getElement() : null;
            if (obj_el != null && obj_el instanceof Element){
                return true;
            }
            else
                return false;
                    
        } catch (Exception e) {
        }
        return false;
    }
    
        private boolean existAction(TXMLObjectAccessor mObjectAccessor, String action) {
    
        TXQuery query = TXQuery.newInstance("for    $b in input()/Action " +
                                            "where  $b/ActionId = '" + action + "' " +
                                            "return $b");
        try {
            TResponse response = mObjectAccessor.xquery(query);
            TXMLObject tobj = response.getFirstXMLObject();
            Object obj_el = tobj != null ? tobj.getElement() : null;
            if (obj_el != null && obj_el instanceof Element){
                return true;
            }
            else
                return false;
                    
        } catch (Exception e) {
        }
        return false;
    }

    private void createTaminoSecurity(String collection, String mDatabaseUri, String domain, String userId, String password) throws URMConnectionException, URMException, TException {
        TConnection secConnect = getConnection (mDatabaseUri, domain, userId, password);
        if (!defaultACLExist(secConnect))createDefaultAcl(secConnect,collection);
        if (!defaultGroupExist(secConnect))createDefaultGroup(secConnect);
    }
    
    private void deleteTaminoSecurity(String collection, String mDatabaseUri, String domain, String userId, String password) throws URMConnectionException, URMException, TException {
        TConnection secConnect = getConnection (mDatabaseUri, domain, userId, password);
        secConnect.useAutoCommitMode();
        if (defaultACLExist(secConnect))deleteDefaultAcl(secConnect);
        if (defaultGroupExist(secConnect))deleteDefaultGroup(secConnect);
    }

    /**
     * Create a <code>org.w3c.dom.Document</code> from the String supplied
     *
     *  @pre        xml != null
     *
     *  @param      xml         The xml to use to create the document
     *
     *  @return     org.w3c.dom.Document        null if error occurs
     **/
    public org.w3c.dom.Document createNewDocument(String xml) {
        org.w3c.dom.Document doc = null;
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setNamespaceAware(false);
            factory.setValidating(false);
            DocumentBuilder builder = factory.newDocumentBuilder();

            //System.out.println( xml );
            doc = builder.parse(new InputSource ( new StringReader (xml) ) );
        }
        catch (Exception e) {
            doc = null;
            e.printStackTrace();
        }
        return doc;
    }
    
    /**
     * Creates the default ACL entry.
     *
     * @pre         database name (database) supplied in the constructor != null
     * @pre         APACHE MUST HAVE A USER XDAV CREATED
     *
     * @return      boolean         true if successfull completed
     *
     * @exception   TException       tamino exception
     **/
    public boolean createDefaultAcl(TConnection taminoConnection, String collection) throws TException {

        boolean result2 = insertSingleDocument(taminoConnection,
            defaultSchemaVersion +
                "\n<ino:acl xmlns:ino=\"" + TAMINO_TSD_3_NAMESPACE_URI +  "\" ino:aclname=\""+WRITE_ACL+"\" >\n"+
                "<ino:ace ino:access=\"full\">"+collection+"</ino:ace>\n"+
                "</ino:acl>");

        //Create the Schema for the ACL group
        boolean result1 = insertSingleDocument(taminoConnection,
            defaultSchemaVersion +
                "\n<ino:acl xmlns:ino=\"" + TAMINO_TSD_3_NAMESPACE_URI +  "\" ino:aclname=\"" + NO_ACL + "\">\n" +
                "<ino:ace ino:access=\"no\">"+collection + "</ino:ace>\n" +
                "</ino:acl>");

        return result1 && result2;
    }
    
    /**
     * Insert a single document.
     *
     * @pre         database name (database) supplied in the constructor != null
     * @pre         APACHE MUST HAVE A USER XDAV CREATED
     * @param       documentString  document string
     * @return      boolean         true if successfull completed
     *
     * @throws      TException
     **/
    public boolean insertSingleDocument(TConnection taminoConnection, String documentString) throws TException {

        TResponse  response = null;
        TXMLObject xmlObject = null;
        boolean    transactionIsOpen = false;
        boolean    result = true;

        try
        {

            xmlObjectAccessor = taminoConnection.newXMLObjectAccessor(TAccessLocation.newInstance(INO_SECURITY_COLLECTION),
                                                                      TDOMObjectModel.getInstance());
            xmlObject = TXMLObject.newInstance( createNewDocument(documentString).getDocumentElement() );
            taminoConnection.useAutoCommitMode();
            taminoTransaction = taminoConnection.useLocalTransactionMode();
            transactionIsOpen = true;
            
            response = xmlObjectAccessor.insert(xmlObject);
            //Commit the Transaction
            taminoTransaction.commit();
            transactionIsOpen = false;
            taminoTransaction = null;

        }
        catch (TInsertException e)  {
            TException nestedException = e.getRootTCause();
            if ( nestedException instanceof TAccessFailureException &&
                    (((TAccessFailureException) nestedException).getReturnValue().equals("8610"))) {

                taminoTransaction.commit();
                transactionIsOpen = false;

            }
            else {
                result = false;
                throw e;
            }

        }
        finally {
            if (transactionIsOpen) taminoTransaction.rollback();
        }
        return result;
    }
    
        /**
     * Creates the default group.
     *
     * @pre         database name (database) supplied in the constructor != null
     * @pre         APACHE MUST HAVE A USER XDAV CREATED
     *
     * @return      boolean         true if successfull completed
     *
     * @exception   TException       tamino exception
     **/
    public boolean createDefaultGroup(TConnection taminoConnection) throws TException {

        //Create the Schema for the Default Group
        String db = url.substring(url.lastIndexOf("/")+1);
        boolean result1 = insertSingleDocument (taminoConnection,
            defaultSchemaVersion +
                "<ino:group xmlns:ino=\"" + TAMINO_TSD_3_NAMESPACE_URI +  "\" ino:groupname= \"" + db + "\">\n"+
                "<ino:aclref>" + NO_ACL + "</ino:aclref>\n" +
                "</ino:group>");

        //Create the default write group and ACL information for xdav user
        boolean result2 = insertSingleDocument (taminoConnection,
            "<ino:group xmlns:ino=\"" + TAMINO_TSD_3_NAMESPACE_URI +  "\" ino:groupname=\""+WRITE_GROUP_NAME+"\">\n"+
                "<ino:userref>"+ metaDataUserName +"</ino:userref>\n"+
                "<ino:aclref>" + WRITE_ACL +"</ino:aclref>\n"+
                "</ino:group>");

        return result1 && result2;
    }
    
        /**
     * Check to see if the default ACL exists
     *
     * @return      boolean         true is returned if default ACL entry exists
     *
     * @throws      TException
     **/
    public boolean defaultACLExist(TConnection taminoConnection) throws TException{
        return getCountDocuments(taminoConnection,"ino:acl[@ino:aclname=\"" + WRITE_ACL + "\"]" ) == 1 &&
            getCountDocuments(taminoConnection,"ino:acl[@ino:aclname=\"" + NO_ACL + "\"]" ) == 1 ;
    }


    /**
     * Check to see if the default Group exists
     *
     * @return      boolean         true is returned if default ACL entry exists
     *
     * @throws      TException
     **/
    public boolean defaultGroupExist(TConnection taminoConnection) throws TException{
        String db = url.substring(url.lastIndexOf("/")+1);
        return getCountDocuments(taminoConnection,"ino:group[@ino:groupname=\"" + WRITE_GROUP_NAME + "\"]" ) == 1 &&
            getCountDocuments(taminoConnection,"ino:group[@ino:groupname=\"" + db + "\"]" ) == 1 ;
    }
    
        /**
     * return the number of response documents for a specific query
     *
     * @return      int     number of found documents
     *
     * @throws      TException
     **/
    private int getCountDocuments(TConnection taminoConnection, String queryString) throws TException{
        int result = 0;
        //Create the XPath query
        TAccessLocation location = TAccessLocation.newInstance( INO_SECURITY_COLLECTION );
        //Create the Object Accessor
        xmlObjectAccessor = taminoConnection.newXMLObjectAccessor( location,
                                                                  TDOMObjectModel.getInstance() );
        //Create the XPath query, in this case check for the database name
        TQuery query = TQuery.newInstance( "count(" + queryString + ")" );

        //Check the response
        TResponse response = xmlObjectAccessor.query( query );
        String s = response.getQueryContentAsString();
        result = Integer.parseInt(response.getQueryContentAsString());
        return result;

    }
    
    private void deleteDefaultGroup(TConnection taminoConnection) {
        TXMLObjectAccessor objectAccessor = null;
        String db = url.substring(url.lastIndexOf("/")+1);
        TAccessLocation location = TAccessLocation.newInstance( INO_SECURITY_COLLECTION );
        objectAccessor = taminoConnection.newXMLObjectAccessor( location,
                                                                  TDOMObjectModel.getInstance() );
        TXQuery query = TXQuery.newInstance("declare namespace ino =\"" + TAMINO_TSD_3_NAMESPACE_URI +  "\" update delete " +
            "input()/ino:group[@ino:groupname=\"" + WRITE_GROUP_NAME + "\"]");
        try {
            TResponse response = objectAccessor.xquery(query);
        } catch (TXQueryException e) {
        }
        query = TXQuery.newInstance("declare namespace ino =\"" + TAMINO_TSD_3_NAMESPACE_URI +  "\" update delete " +
            "input()/ino:group[@ino:groupname=\"" + db + "\"]");
        try {
            TResponse response = objectAccessor.xquery(query);
        } catch (TXQueryException e) {
        }
    }
    
    private void deleteDefaultAcl(TConnection taminoConnection) {
        TXMLObjectAccessor objectAccessor = null;
        String db = url.substring(url.lastIndexOf("/")+1);
        TAccessLocation location = TAccessLocation.newInstance( INO_SECURITY_COLLECTION );
        objectAccessor = taminoConnection.newXMLObjectAccessor( location,
                                                                  TDOMObjectModel.getInstance() );
        TXQuery query = TXQuery.newInstance("declare namespace ino =\"" + TAMINO_TSD_3_NAMESPACE_URI +  "\" update delete " +
            "input()/ino:acl[@ino:aclname=\"" + WRITE_ACL + "\"]");
        try {
            TResponse response = objectAccessor.xquery(query);
        } catch (TXQueryException e) {
        }
        query = TXQuery.newInstance("declare namespace ino =\"" + TAMINO_TSD_3_NAMESPACE_URI +  "\" update delete " +
            "input()/ino:acl[@ino:aclname=\"" + NO_ACL + "\"]");
        try {
            TResponse response = objectAccessor.xquery(query);
        } catch (TXQueryException e) {
        }
    }
    

    public boolean createAdminRoleMapping(String admin, String domain, String role, TConnection taminoConnection, String collection)
            throws URMInternalServerException {
    
        TXMLObjectAccessor objectAccessor = null;
        TAccessLocation location = TAccessLocation.newInstance(collection);
        objectAccessor = taminoConnection.newXMLObjectAccessor( location,
                                                                  TDOMObjectModel.getInstance() );
        TXQuery query = TXQuery.newInstance("for    $b in input()/UserRoleMapping " +
                                            "where  $b/Role = '" + role + "' " +
                                            "return $b/UserName");
        try {
            TResponse response = objectAccessor.xquery(query);
            TXMLObjectIterator iter = response.getXMLObjectIterator();
            if (!response.hasFirstXMLObject()) {
                return true;
            }
            while (iter != null && iter.hasNext()) {
                String userName = null, userDomain = null;
                TXMLObject tobj = iter.next();
                Object obj_el = tobj != null ? tobj.getElement() : null;
                if (obj_el != null && obj_el instanceof org.w3c.dom.Element) {
                    org.w3c.dom.Node node = ((org.w3c.dom.Element)obj_el).getFirstChild();
                    if (node != null) {
                        userName = node.getNodeValue();
                    }
                    
                    org.w3c.dom.NamedNodeMap usrAttr = ((org.w3c.dom.Element)obj_el).getAttributes();
                    if (usrAttr != null) {
                        Node usrDomainNode = usrAttr.getNamedItem("Domain");
                        if (usrDomainNode != null) {
                            userDomain = usrDomainNode.getNodeValue();
                        }
                    }
                        
                    if ((userName != null) && (userName.equals(admin))) {
                        if (userDomain == null) {
                            if (domain == null) return false;
                        } else {
                            if ((domain != null) && (userDomain.equals(domain))) return false;
                        }
                    }
                }
                throw new URMInternalServerException (MessageLogger.getAndLogMessage(msLogger, "URMCOE0052", domain + "/" + admin));
            }
            return true;
        } catch (Exception e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    }
}

