/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/store/org/apache/slide/store/tamino/security/admin/URMUserDBStore.java,v 1.4 2004/09/15 14:58:25 pnever Exp $
 * $Revision: 1.4 $
 * $Date: 2004/09/15 14:58:25 $
 *
 * ====================================================================
 *
 * 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.store.tamino.security.admin;

import com.softwareag.common.instrumentation.logging.Level;
import com.softwareag.common.instrumentation.logging.Logger;
import com.softwareag.common.instrumentation.logging.LoggerFactory;
import com.softwareag.common.instrumentation.logging.LoggerUtil;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.Vector;
import javax.transaction.xa.XAException;
import javax.transaction.xa.Xid;
import org.apache.slide.authenticate.CredentialsToken;
import org.apache.slide.common.NamespaceAccessToken;
import org.apache.slide.common.ServiceAccessException;
import org.apache.slide.common.ServiceConnectionFailedException;
import org.apache.slide.common.ServiceDisconnectionFailedException;
import org.apache.slide.common.ServiceInitializationFailedException;
import org.apache.slide.common.Uri;
import org.apache.slide.content.NodeProperty;
import org.apache.slide.content.NodeProperty.NamespaceCache;
import org.apache.slide.content.NodeRevisionContent;
import org.apache.slide.content.NodeRevisionDescriptor;
import org.apache.slide.content.NodeRevisionDescriptors;
import org.apache.slide.content.NodeRevisionNumber;
import org.apache.slide.content.RevisionAlreadyExistException;
import org.apache.slide.content.RevisionDescriptorNotFoundException;
import org.apache.slide.content.RevisionNotFoundException;
import org.apache.slide.lock.LockTokenNotFoundException;
import org.apache.slide.lock.NodeLock;
import org.apache.slide.macro.ForbiddenException;
import org.apache.slide.security.NodePermission;
import org.apache.slide.store.tamino.common.XForbiddenException;
import org.apache.slide.store.tamino.common.XGlobals;
import org.apache.slide.store.tamino.jdomobjects.XFactory;
import org.apache.slide.store.tamino.store.XMemoryStore;
import org.apache.slide.store.tamino.tools.stores.ActionDeclaration;
import org.apache.slide.structure.ObjectAlreadyExistsException;
import org.apache.slide.structure.ObjectNode;
import org.apache.slide.urm.common.URMPrincipal;
import org.apache.slide.util.ClassName;
import org.apache.slide.util.XMLValue;
import org.apache.slide.util.XUri;
import org.apache.slide.webdav.util.AclConstants;
import org.apache.slide.webdav.util.WebdavConstants;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.output.XMLOutputter;


/**
 ** URM Security store. This store serves all requests of URI' equals to
 ** .../administartion/security/userdb.
 **
 ** @author    josef.haiduk@softwareag.com
 ** @version   $Revision: 1.4 $
 **
 **/
public class URMUserDBStore extends XMemoryStore {
    private static final String LOGNAME = LoggerUtil.getThisClassName();
    private static final String CLASSNAME = new ClassName(LOGNAME).getPlainName();
    private static Logger logger = LoggerFactory.getLogger(LOGNAME);
    
    CredentialsToken credentialsToken = null;
    String domain = null;
    
    Hashtable connectManager = new Hashtable();
    private boolean isConnected = false;
    static String PRINCIPAL = "<principal/>";
    static String COLLECTION = "<collection/>";
    static String RESOURCETYPE = "resourcetype";
    
    public static String GRANT_PRIVILEGE_SET = "grant-privilege-set";
    public static String DENY_PRIVILEGE_SET = "deny-privilege-set";
    public static String PRIVILEGE_MEMBER_SET = "privilege-member-set";
    
    static String userDBPath = null;
    static String usersPath = null;
    static String groupsPath = null;
    static String rolesPath = null;
    static String userCollection = null;
    static String groupCollection = null;
    static String roleCollection = null;
    static XUri userDBUri = null;
    
    static String DEFAULT_PASSWORD_KEY = "defaultPasswordPolicy";
    static String DEFAULT_PASSWORD = "the default password is Administrator";
    
    private static XMLOutputter xmlOut = new XMLOutputter();
    
    public URMUserDBStore() {
        super();
    }
    
    public synchronized void initialize( NamespaceAccessToken token )
        throws ServiceInitializationFailedException {
        super.initialize( token );
        if ( initialized ) {
            usersPath = namespace.getConfig().getUsersPath();
            groupsPath = namespace.getConfig().getGroupsPath();
            rolesPath = namespace.getConfig().getRolesPath();
            
            userCollection = new XUri(usersPath).lastSegment();
            groupCollection = new XUri(groupsPath).lastSegment();
            roleCollection = new XUri(rolesPath).lastSegment();
            userDBUri = new XUri(usersPath).getParent();
            userDBPath = userDBUri.toString();
        }
    }
    
    static String getUsersPath() {
        return usersPath;
    }
    
    static String getGroupsPath() {
        return groupsPath;
    }
    
    static String getRolesPath() {
        return rolesPath;
    }
    
    static String getUserDBPath() {
        return userDBPath;
    }
    
    static XUri getUserDBUri() {
        return userDBUri;
    }
    
    public synchronized void createObject(Uri uri, ObjectNode object)
        throws ServiceAccessException, ObjectAlreadyExistsException {
        logEnter("createObject", uri);
        String uriStr = uri.toString();
        
        if ( uriStr.compareTo(userDBPath) == 0 ||
            uriStr.compareTo(usersPath) == 0 ||
            uriStr.compareTo(groupsPath) == 0 ||
            uriStr.compareTo(rolesPath) == 0 ||
            uriStr.startsWith(ActionDeclaration.SCOPE) )
            super.createObject(uri, object);
        else
            throw new ServiceAccessException( this,
                                             new ForbiddenException(uri.toString(), new XForbiddenException( "access is forbidden" )) );
        /*
         if ( ! org.apache.slide.util.Configuration.useIntegratedSecurity() ) {
         super.createObject(uri, object);
         return;
         }
         
         if ( uriStr.length() > scope.toString().length() )
         throw new ServiceAccessException( this,
         new ForbiddenException(uri.toString(), new XForbiddenException( "access is forbidden" )) );
         */
    }
    /*
     public synchronized ObjectNode retrieveObject(Uri uri)
     throws ServiceAccessException, ObjectNotFoundException {
     
     logEnter("retrieveObject", uri);
     String uriStr = uri.toString();
     Vector children = new Vector();
     ObjectNode result = new SubjectNode(uriStr, children, new Vector());
     
     if ( ! org.apache.slide.util.Configuration.useIntegratedSecurity() ) {
     return super.retrieveObject(uri);
     }
     
     if ( getPrincipal() == null )
     return result;
     
     if (!uriStr.equals(userDBPath))
     throw new ObjectNotFoundException(uriStr);
     
     if ( usersPath != null )
     children.add(usersPath);
     
     if ( groupsPath != null )
     children.add(groupsPath);
     
     if ( rolesPath != null )
     children.add(rolesPath);
     
     return new SubjectNode(uriStr, children, new Vector());
     }
     
     public void storeObject(Uri uri, ObjectNode object)
     throws ServiceAccessException, ObjectNotFoundException {
     
     if ( ! org.apache.slide.util.Configuration.useIntegratedSecurity() ) {
     super.storeObject(uri, object);
     }
     }
     
     public void removeObject(Uri uri, ObjectNode object)
     throws ServiceAccessException, ObjectNotFoundException {
     logEnter("removeObject", uri);
     
     throw new ServiceAccessException( this,
     new ForbiddenException(uri.toString(), new XForbiddenException( "access is forbidden" )) );
     
     }
     */
    public void createRevisionDescriptors(Uri uri, NodeRevisionDescriptors revisionDescriptors)
        throws ServiceAccessException {
        logEnter("createRevisionDescriptors", uri);
        if (! org.apache.slide.util.Configuration.useIntegratedSecurity()) {
            super.createRevisionDescriptors(uri, revisionDescriptors);
            return;
        }
    }
    
    public synchronized NodeRevisionDescriptors retrieveRevisionDescriptors(Uri uri)
        throws ServiceAccessException, RevisionDescriptorNotFoundException {
        
        logEnter("retrieveRevisionDescriptors", uri);
        if (! org.apache.slide.util.Configuration.useIntegratedSecurity()) {
            NodeRevisionDescriptors result = super.retrieveRevisionDescriptors(uri);
            return result;
        }
        else {
            return XFactory.createNRDs(uri.toString());
        }
    }
    
    public void storeRevisionDescriptors(Uri uri, NodeRevisionDescriptors revisionDescriptors)
        throws ServiceAccessException, RevisionDescriptorNotFoundException {
        logEnter("storeRevisionDescriptors", uri);
        if (! org.apache.slide.util.Configuration.useIntegratedSecurity()) {
            super.storeRevisionDescriptors(uri, revisionDescriptors);
            return;
        }
    }
    
    public synchronized void removeRevisionDescriptors(Uri uri) throws ServiceAccessException {
        logEnter("removeRevisionDescriptors",uri);
        if (! org.apache.slide.util.Configuration.useIntegratedSecurity()) {
            super.removeRevisionDescriptors(uri);
            return;
        }
    }
    
    public synchronized NodeRevisionDescriptor retrieveRevisionDescriptor
        (Uri uri, NodeRevisionNumber revisionNumber)
        throws ServiceAccessException, RevisionDescriptorNotFoundException {
        
        logEnter("retrieveRevisionDescriptor", uri);
        if (! org.apache.slide.util.Configuration.useIntegratedSecurity()) {
            NodeRevisionDescriptor result = super.retrieveRevisionDescriptor(uri, revisionNumber);
            return result;
        }
        else {
            return XFactory.createNRD(uri.toString(), COLLECTION);
        }
    }
    
    public void createRevisionDescriptor(Uri uri, NodeRevisionDescriptor revisionDescriptor)
        throws ServiceAccessException {
        logEnter("createRevisionDescriptor", uri);
        if (! org.apache.slide.util.Configuration.useIntegratedSecurity()) {
            super.createRevisionDescriptor(uri, revisionDescriptor);
            return;
        }
    }
    
    public synchronized void removeRevisionDescriptor(Uri uri, NodeRevisionNumber number)
        throws ServiceAccessException {
        logEnter("removeRevisionDescriptor",uri);
        if (! org.apache.slide.util.Configuration.useIntegratedSecurity()) {
            super.removeRevisionDescriptor(uri, number);
            return;
        }
    }
    
    public void storeRevisionDescriptor
        (Uri uri, NodeRevisionDescriptor revisionDescriptor)
        throws ServiceAccessException, RevisionDescriptorNotFoundException {
        logEnter("storeRevisionDescriptor",uri);
        if (! org.apache.slide.util.Configuration.useIntegratedSecurity()) {
            super.storeRevisionDescriptor(uri, revisionDescriptor);
            return;
        }
        if ( getPrincipal() == null ) {
            return;
        }
        NodeProperty sync = revisionDescriptor.getProperty("sync", XGlobals.TAMINO_NAMESPACE_URI);
        if ( sync != null  ) {
            URMGate gate = new URMGate(this, uri.toString());
            gate.synchronize();
        }
    }
    
    public synchronized NodeRevisionContent retrieveRevisionContent(
        Uri uri, NodeRevisionDescriptor revisionDescriptor)
        throws ServiceAccessException, RevisionNotFoundException {
        logEnter("retrieveRevisionContent", uri);
        String uriStr = uri.toString();
        
        NodeRevisionContent result = new NodeRevisionContent();
        result.setContent(uriStr.toCharArray());
        return result;
    }
    
    public synchronized void storeRevisionContent( Uri uri, NodeRevisionDescriptor revisionDescriptor,
                                                  NodeRevisionContent revisionContent)
        throws ServiceAccessException, RevisionNotFoundException {
        logEnter("storeRevisionContent", uri);
    }
    
    public synchronized void createRevisionContent( Uri uri, NodeRevisionDescriptor revisionDescriptor,
                                                   NodeRevisionContent revisionContent )
        throws ServiceAccessException, RevisionAlreadyExistException {
        logEnter("createRevisionContent",uri);
    }
    
    public synchronized void removeRevisionContent( Uri uri, NodeRevisionDescriptor revisionDescriptor )
        throws ServiceAccessException {
        logEnter("removeRevisionContent",uri);
    }
    
    public synchronized void connect(CredentialsToken crdtoken) throws ServiceConnectionFailedException {
        try {
            if ( crdtoken == null ) {
                connect();
                return;
            }
            logEnter("connect with crdtoken");
            
            if ( credentialsToken != null )
                if (credentialsToken.equals(crdtoken) )
                    return;
            
            credentialsToken = crdtoken;
            URMPrincipal principal = getPrincipal(crdtoken);
            if ( principal != null ) {
                URMPrincipal priviousPrincipal = getPrincipal();
                if ( priviousPrincipal != null ) {
                    //if ( priviousPrincipal.getName().compareTo(principal.getName()) == 0 )
                    if ( priviousPrincipal.equals(principal))
                        return;
                }
                connectManager.put(Thread.currentThread().getName(), new StoreInfo(principal));
                domain = principal.getDomain();
                if ( domain != null && domain.length() == 0 )
                    domain = null;
            }
        }
        catch (Exception e) {
            throw new ServiceConnectionFailedException(this, e);
        }
    }
    
    public synchronized void connect() throws ServiceConnectionFailedException {
        logEnter("connect");
        credentialsToken = null;
        domain = null;
    }
    
    public synchronized boolean connectIfNeeded(CredentialsToken token)
        throws ServiceConnectionFailedException, ServiceAccessException {
        logEnter("connectIfNeeded with CredentialsToken");
        if ( credentialsToken.equals(token) )
            return false;
        else
            this.connect(token);
        return true;
    }
    
    public synchronized boolean connectIfNeeded()
        throws ServiceConnectionFailedException, ServiceAccessException {
        logEnter("connectIfNeeded");
        
        // we return true to say we were not connected
        return true;
    }
    
    public synchronized boolean isConnected() throws ServiceAccessException {
        
        // we say false and manage this in connect
        return false;
        
    }
    
    public synchronized void disconnect() throws ServiceDisconnectionFailedException {
        logEnter("disconnect");
        connectManager.remove(Thread.currentThread().getName());
    }
    
    synchronized URMPrincipal getPrincipal()
        throws ServiceAccessException {
        String currentThread = Thread.currentThread().getName();
        if ( connectManager.containsKey(currentThread))
            return ((StoreInfo)connectManager.get(currentThread)).getPrincipal();
        else {
            return null;
        }
    }
    
    StoreInfo getStoredInfo() {
        return ((StoreInfo)connectManager.get(Thread.currentThread().getName()));
    }
    
    private URMPrincipal getPrincipal(CredentialsToken credentialsToken) {
        
        java.security.Principal principal = credentialsToken.getPrincipal();
        if ( !(principal instanceof URMPrincipal))
            return null;
        
        return (URMPrincipal) principal;
    }
    
    static void insertPrincipalUrl(NodeRevisionDescriptor nrd, String path) {
        String uri = path;
        NodeProperty principal_url = new NodeProperty(AclConstants.P_PRINCIPAL_URL, createHrefValue(uri));
        nrd.setProperty(principal_url);
    }
    
    static void insertAlternateUriSet(NodeRevisionDescriptor nrd, String value) {
        NodeProperty alternateUriSet = new NodeProperty(AclConstants.P_ALTERNATE_URI_SET, value, true);
        nrd.setProperty(alternateUriSet);
    }
    
    void insertGroupmemberShip(NodeRevisionDescriptor nrd, String path, Set members)
        throws ServiceAccessException {
        try {
            String uri = path;
            NodeProperty group_membership = nrd.getProperty(AclConstants.P_GROUP_MEMBERSHIP);
            XMLValue value = null;
            if ( group_membership != null ) {
                value = new XMLValue((String)group_membership.getValue());
            }
            group_membership = new NodeProperty(AclConstants.P_GROUP_MEMBERSHIP,
                                                buildHrefOfMemeber(value, uri, members).toString(),true);
            nrd.setProperty(group_membership);
        }
        catch (JDOMException e ) {
            throw new ServiceAccessException(this ,e);
        }
    }
    
    void insertGroupmemberSet(NodeRevisionDescriptor nrd, String path, Set members)
        throws ServiceAccessException {
        try {
            String uri = path;
            NodeProperty group_member_set = nrd.getProperty(AclConstants.P_GROUP_MEMBER_SET);
            XMLValue value = null;
            if ( group_member_set != null ) {
                value = new XMLValue((String)group_member_set.getValue());
            }
            group_member_set = new NodeProperty(AclConstants.P_GROUP_MEMBER_SET,
                                                buildHrefOfMemeber(value, uri, members).toString(), false);
            nrd.setProperty(group_member_set);
        }
        catch (JDOMException e ) {
            throw new ServiceAccessException(this ,e);
        }
    }
    
    
    void insertActionmemberSet(NodeRevisionDescriptor nrd, String path, Map map)
        throws ServiceAccessException {
        
        try {
            HashSet grantSet = new HashSet();
            HashSet denySet = new HashSet();
            
            Iterator i = map.keySet().iterator();
            while ( i.hasNext() ) {
                String key = (String)i.next();
                Boolean b = (Boolean)map.get(key);
                if ( b.booleanValue() )
                    grantSet.add(key);
                else
                    denySet.add(key);
            }
            
            insertSubjectProperty(nrd, GRANT_PRIVILEGE_SET, buildPrivilegeOfMember(grantSet) ,false);
            insertSubjectProperty(nrd, DENY_PRIVILEGE_SET, buildPrivilegeOfMember(denySet) ,false);
        }
        catch (Exception e ) {
            throw new ServiceAccessException(this ,e);
        }
    }
    
    private XMLValue buildPrivilegeOfMember(Set members) {
        XMLValue result = new XMLValue();
        Iterator iter = members.iterator();
        while (iter.hasNext()) {
            Object o = iter.next();
            String item = "";
            if ( o.getClass().isInstance(item) )
                item = (String)o;
            else
                item = URMGate.getSubjectName(o);
            if ( item.length() > 0 ) {
                result.add(createPrivilegeElement(item));
            }
        }
        return result;
    }
    
    private Element createPrivilegeElement(String item) {
        Element result = new Element(AclConstants.E_PRIVILEGE, NamespaceCache.DEFAULT_NAMESPACE);
        Element itemElm = new Element(item, NamespaceCache.DEFAULT_NAMESPACE);
        result.addContent(itemElm);
        return result;
    }
    
    void insertPrivilegememberSet(NodeRevisionDescriptor nrd, String path, Set set)
        throws ServiceAccessException {
        try {
            //          insertSubjectProperty(nrd, PRIVILEGE_MEMBER_SET, buildHrefOfMemeber(null, path, set) ,false);
            NodeProperty subjectsProperty = new NodeProperty(PRIVILEGE_MEMBER_SET,buildHrefOfMemeber(null, path, set),
                                                             "DAV:", "", false);
            nrd.setProperty(subjectsProperty);
        }
        catch (Exception e ) {
            throw new ServiceAccessException(this ,e);
        }
    }
    static void insertDisplayname(NodeRevisionDescriptor nrd, String displayname) {
        if ( displayname == null || displayname.equals("") )
            return;
        nrd.setProperty(WebdavConstants.P_DISPLAYNAME, displayname);
    }
    
    void insertDomainname(NodeRevisionDescriptor nrd) {
        if ( domain == null )
            return;
        insertSubjectProperty(nrd, "domain", domain, true);
    }
    
    static void insertSubjectProperty(NodeRevisionDescriptor nrd, String key, Object value, boolean protection) {
        NodeProperty subjectsProperty = new NodeProperty(key,value,
                                                         XGlobals.TAMINO_NAMESPACE_URI, "", protection);
        nrd.setProperty(subjectsProperty);
    }
    
    static void insertSubjectProperties(NodeRevisionDescriptor nrd, Properties properties) {
        Enumeration en = properties.propertyNames();
        while (en.hasMoreElements() ) {
            String key = (String)en.nextElement();
            String value = (String)properties.get(key);
            insertSubjectProperty(nrd,key,value,false);
        }
    }
    
    static void insertSubjectProperties(NodeRevisionDescriptor nrd, Properties properties, Map map) {
        Set set = map.keySet();
        Iterator i = set.iterator();
        while (i.hasNext() ) {
            String key = (String)i.next();
            String value = (String)properties.get(key);
            boolean protectedProp = !((Boolean)map.get(key)).booleanValue();
            insertSubjectProperty(nrd,key,value,protectedProp);
        }
    }
    
    
    // the method creates a href element out of an uri
    static Object createHrefValue( String uri ) {
        Element href = new Element( AclConstants.E_HREF, NamespaceCache.DEFAULT_NAMESPACE );
        href.addContent( uri );
        return xmlOut.outputString( href );
    }
    
    // creates a group-membership element containing the groups as child elements
    static XMLValue buildHrefOfMemeber(XMLValue existingValue, String path, Set members )
        throws JDOMException {
        XMLValue value = new XMLValue();
        if ( existingValue != null )
            value = existingValue;
        if (members == null) {
            value.add((String) createHrefValue(path));
            return value;
        }
        Iterator iter = members.iterator();
        while (iter.hasNext()) {
            Object o = iter.next();
            String item = "";
            if ( o.getClass().isInstance(item) )
                item = (String)o;
            else
                item = URMGate.getSubjectName(o);
            if ( item.length() > 0 ) {
                item = "/" + item;
                value.add((String) createHrefValue(path + item));
            }
        }
        return value;
    }
    
    public void putLock(Uri uri, NodeLock lock) throws ServiceAccessException {
        throw new ServiceAccessException(this,
                                         new ForbiddenException(uri.toString(),
                                                                new XForbiddenException("LOCK not allowed in security store")));
    }
    
    public void renewLock(Uri uri, NodeLock lock)
        throws ServiceAccessException, LockTokenNotFoundException {
        throw new ServiceAccessException(this,
                                         new ForbiddenException(uri.toString(),
                                                                new XForbiddenException("LOCK not allowed in security store")));
    }
    
    public void removeLock(Uri uri, NodeLock lock)
        throws ServiceAccessException, LockTokenNotFoundException {
        throw new ServiceAccessException(this,
                                         new ForbiddenException(uri.toString(),
                                                                new XForbiddenException("LOCK not allowed in security store")));
    }
    
    public void killLock(Uri uri, NodeLock lock)
        throws ServiceAccessException, LockTokenNotFoundException {
        throw new ServiceAccessException(this,
                                         new ForbiddenException(uri.toString(),
                                                                new XForbiddenException("LOCK not allowed in security store")));
    }
    
    public synchronized Enumeration enumerateLocks(Uri uri) throws ServiceAccessException {
        logEnter("enumerateLocks", uri);
        Vector locksVector = new Vector();
        Enumeration result = locksVector.elements();
        return result;
    }
    
    public void grantPermission(Uri uri, NodePermission permission)
        throws ServiceAccessException {
    }
    public void revokePermission(Uri uri, NodePermission permission)
        throws ServiceAccessException {
    }
    public void revokePermissions(Uri uri)
        throws ServiceAccessException {
    }
    public Enumeration enumeratePermissions(Uri uri) throws ServiceAccessException {
        
        String uriStr = uri.toString();
        logEnter("enumeratePermissions called " + uriStr);
        Vector permissionsVector = null;
        permissionsVector = new Vector();
        Enumeration result = permissionsVector.elements();
        return result;
    }
    
    public void start(Xid xid, int flags)
        throws XAException {
        super.start( xid, flags );
        logEnter("start");
    }
    
    public void commit( Xid xid, boolean onePhase ) throws XAException {
        
        super.commit( xid, onePhase );
        connectManager.remove(Thread.currentThread().getName());
        logEnter("commit");
    }
    
    public void rollback( Xid xid ) throws XAException {
        
        super.rollback( xid );
        connectManager.remove(Thread.currentThread().getName());
        logEnter("rollback");
    }
    
    public void forget( Xid xid ) throws XAException {
        
        super.rollback( xid );
        connectManager.remove(Thread.currentThread().getName());
        logEnter("rollback");
    }
    
    private void logEnter(String method) {
        if( logger.isLoggable(Level.FINE) ) logger.entering( CLASSNAME, method);
    }
    private void logEnter(String method, Uri uri) {
        if( logger.isLoggable(Level.FINE) ) logger.entering( CLASSNAME, method, new Object[] {uri} );
    }
    
}



























