/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/store/org/apache/slide/store/tamino/servlet/XWebdavServlet.java,v 1.5 2005/01/19 15:19:52 pnever Exp $
 * $Revision: 1.5 $
 * $Date: 2005/01/19 15:19:52 $
 *
 * ====================================================================
 *
 * 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.servlet;

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.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.slide.store.tamino.datastore.XConnectionPool;
import org.apache.slide.store.tamino.jdomobjects.XUuri;
import org.apache.slide.store.tamino.store.monitoring.IMonitor;
import org.apache.slide.store.tamino.store.monitoring.IMonitorable;
import org.apache.slide.store.tamino.store.monitoring.Monitor;
import org.apache.slide.store.tamino.store.monitoring.MonitoredCounter;
import org.apache.slide.store.tamino.store.monitoring.MonitoredTimer;
import org.apache.slide.store.tamino.tools.Env;
import org.apache.slide.store.tamino.tools.stores.ActionDeclaration;
import org.apache.slide.util.ClassName;
import org.apache.slide.util.Misc;
import org.apache.slide.util.XUri;
import org.apache.slide.webdav.WebdavServlet;
import org.apache.slide.webdav.util.WebdavStatus;


/**
 ** Adds monitoring.
 **
 ** @author    peter.nevermann@softwareag.com
 ** @version   $Revision: 1.5 $
 **/
public class XWebdavServlet extends WebdavServlet implements IMonitorable {
    
    private static final String LOGNAME = LoggerUtil.getThisClassName();
    private static final String CLASSNAME = new ClassName(LOGNAME).getPlainName();
    private static Logger logger = LoggerFactory.getLogger(LOGNAME);
    
    /** Product information **/
    protected final static String PRODUCT_INFORMATION = "Product Information";
    
    /** product information */
    protected String version = null;
    
    /** the name */
    protected String monName = null;
    /** the parent */
    protected IMonitorable monParent = null;
    /** the children */
    protected List monChildren = new ArrayList();
    /** the Monitor object */
    protected Monitor monitor = null;
    
    // monitoring counters and timers...
    /** method -> counterName*/
    private Map counterNames = new HashMap();
    /** counterName -> counter*/
    private Map counters = new HashMap();
    /** method -> timerName*/
    private Map timerNames = new HashMap();
    /** timerName -> timer*/
    private Map timers = new HashMap();
    
    
    
    /**
     * Overwrites in order to init monitoring.
     * @exception ServletException servlet error
     */
    public void init() throws ServletException {
        if( logger.isLoggable(Level.FINE) )
            logger.entering( CLASSNAME, "init" );
        
        // monitoring variables
        //this.monName = "WebdavServlet";
        this.monName = "WebDAV Servlet";
        // this.monParent = ...; no parent monitorable
        // this.monChildren.add( ... ); // no children
        this.monitor = Monitor.getMonitor( this, true ); // this comes last!! - displaceRoot=true
        
        try {
            version = Env.get().getVersion();
        } catch (IOException e) {
            throw new ServletException("error obtaining product version", e);
        }
        
        monitor.registerProperty( PRODUCT_INFORMATION );
        
        printVersion();
        
        if (XUuri.getScopes() == null) {
            XUuri.initStoreScopes(getInitParameter("namespace"));
        }
        super.init();
        
        if( logger.isLoggable(Level.FINE) )
            logger.exiting( CLASSNAME, "init" );
    }
    
    private void printVersion() {
        Class cl;
        
        System.out.println( version);
        
        cl = DocumentBuilderFactory.newInstance().getClass();
        System.out.println("Xerces Name: " + Misc.getXercesName());
        System.out.println(cl.getName() + " loaded from " + Misc.locateClasspathItem(cl));
    }
    
    /**
     * Destroy servlet.
     */
    public void destroy() {
        XConnectionPool.closeConnectionPool();
        super.destroy();
        XUuri.clearScopes();
    }
    
    /**
     * Get counter for method
     */
    private synchronized MonitoredCounter counter( String method ) {
        String name = (String)counterNames.get( method );
        if( name == null ) {
            name = method+" [#]";
            counterNames.put( method, name );
        }
        MonitoredCounter result = (MonitoredCounter)counters.get( name );
        if( result == null ) {
            result = monitor.getCounter( name );
            counters.put( name, result );
        }
        
        return result;
    }
    
    /**
     * Get counter for method
     */
    private synchronized MonitoredTimer timer( String method ) {
        String name = (String)timerNames.get( method );
        if( name == null ) {
            name = method+" [ms]";
            timerNames.put( method, name );
        }
        MonitoredTimer result = (MonitoredTimer)timers.get( name );
        if( result == null ) {
            result = monitor.getTimer( name );
            timers.put( name, result );
        }
        
        return result;
    }
    
    
    /**
     * Overwrites in order to perform monitoring.
     * @param req http servlet request
     * @param resp http servlet response
     * @exception ServletException servlet error
     * @exception IOException io error
     */
    protected void service (HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
        if( logger.isLoggable(Level.FINE) )
            logger.entering( CLASSNAME, "service", new Object[]{req.getMethod(),req.getRequestURI()} );
        
        String m = req.getMethod();
        counter(m).increment();
        Object timerId = timer(m).start();
        
        if ("PUT".equals(m) ) {
            String uri = req.getRequestURI();
            String securityPath = new XUri(ActionDeclaration.SCOPE).getParent().toString();
            String server = this.token.getName();
            if ( uri.startsWith("/"+server+securityPath)) {
                resp.setStatus(WebdavStatus.SC_FORBIDDEN,
                               WebdavStatus.getStatusText(WebdavStatus.SC_FORBIDDEN)
                                   +" - PUT not allowed in security store");
                return;
            }
        }
        
        super.service( req, resp );
        
        timer(m).stop(timerId);
        
        if( logger.isLoggable(Level.FINE) )
            logger.exiting( CLASSNAME, "service" );
    }
    
    //-------------------------------------------------------------
    // IMonitorable interface
    // ------------------------------------------------------------
    
    /**
     ** Return the name of this monitorable.
     **
     ** @return the name
     **
     **/
    public String getMonName() {
        return monName;
    }
    
    /**
     ** Get the parent monitorable.
     **
     ** @return the parent, null if none
     **
     **/
    public IMonitorable getMonParent() {
        return monParent;
    }
    
    /**
     ** Get child monitorables.
     **
     ** @return  the children
     **
     **/
    public List getMonChildren() {
        return monChildren;
    }
    
    /**
     ** Get the Monitor object.
     **
     ** @return the monitor object
     **
     **/
    public IMonitor getMonitor() {
        return monitor;
    }
    
    /**
     ** Get the value of a registered property.
     ** @param prop property name
     ** @return the value of the indicated property as String
     **
     **/
    public Object getMonProperty( String prop ) {
        Object result = null;
        
        if (PRODUCT_INFORMATION.equals (prop)) {
            result = version;
        }
        
        return result;
    }
    
}



