 /*
 * ====================================================================
 *
 * Copyright 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.event;

import java.io.IOException;
import java.util.Hashtable;

import javax.servlet.http.HttpServletRequest;

import org.apache.slide.common.Domain;
import org.apache.slide.common.ServiceAccessException;
import org.apache.slide.common.SlideToken;
import org.apache.slide.content.Content;
import org.apache.slide.content.InsufficientStorageException;
import org.apache.slide.content.NodeRevisionDescriptor;
import org.apache.slide.content.NodeRevisionDescriptors;
import org.apache.slide.content.RevisionDescriptorNotFoundException;
import org.apache.slide.content.RevisionNotFoundException;
import org.apache.slide.lock.ObjectLockedException;
import org.apache.slide.security.AccessDeniedException;
import org.apache.slide.structure.LinkedObjectNotFoundException;
import org.apache.slide.structure.ObjectNotFoundException;
import org.apache.slide.util.conf.Configurable;
import org.apache.slide.util.conf.Configuration;
import org.apache.slide.util.conf.ConfigurationException;
import org.apache.slide.util.logger.Logger;
import org.apache.slide.webdav.event.DetailedWebdavEvent;
import org.apache.slide.webdav.event.WebdavAdapter;
import org.apache.slide.webdav.event.WebdavEvent;
import org.apache.slide.webdav.method.AbstractWebdavMethod;

/**
 * 
 * @author tbellemb
 * @version 1.1.0-RC1
 * 
 * The QuotaListener class manages quota on the server.
 * @link http://esup-portail.org/consortium/espace/Stockage_2F/serveur/documents/specifications/specifWebDAVQuotas.html
 * 
 * Modifications : 
 * 2005.07.12 : Exporting the QuotaElement class and constants
 *  
 */

public class QuotaListener extends WebdavAdapter implements ContentListener, Configurable {

	// logger
	private static final String LOG_CHANNEL = "org.apache.slide.event.QuotaListener";

	// path on which quota are applied
	private static String quotaPath;
	
	// it is required to save the content length of a resource to be deleted to update the resource quota MD
	// after the deletion - an hashtable does the job
	private Hashtable tableOfResourceLength;

	// objects stored in the hashtable below
	// we use Object to take advantage of the garbage collector
	private class ResourceLengthElement {
		
		private String uri;
		private String contentLength;
		
		public ResourceLengthElement (String uri, long contentLength) {
			this.uri = uri;
			this.contentLength = String.valueOf((int)contentLength);
			
		}// resourceLengthElement
		
		public ResourceLengthElement (String uri, int contentLength) {
			this.uri = uri;
			this.contentLength = String.valueOf(contentLength);
			
		}// resourceLengthElement
		
		public ResourceLengthElement (String uri, String contentLength) {
			this.uri = uri;
			this.contentLength = contentLength;
		}// ResourceLengthElement
		
		public String getContentLength() {
			return contentLength;
		}
		
	}// resourceLengthElement

	
	/**
	 * 
	 * @param uri to process
	 * @param path Does the uri start with this path ?
	 * @return true if the uri starts with the path, else false
	 */
	private boolean match(String uri, String path) {
		boolean result = false;
		
		if (path=="") return true; // no path parameter = all of the tree processed
		
		String [] pathArray = path.split(";");
		
		for (int i=0; i<pathArray.length; i++) {
			result = result || uri.startsWith(pathArray[i]);
		}// for (int i=0; i<pathArray.length; i++)
		
		return result;
	}// match
	
	
	public QuotaListener(){
		tableOfResourceLength = new Hashtable();
	}// constructor
	
	
	/**
	 * Called before a resource is about to be deleted
	 * - save the resource content lenght for the deleteAfterDelete method
	 */
	public void deleteBeforeDelete(DetailedWebdavEvent event) throws VetoException {
		
		Domain.log("deleteBeforeDelete", LOG_CHANNEL, Logger.DEBUG);
		
		AbstractWebdavMethod method = (AbstractWebdavMethod)event.getSource();
		HttpServletRequest request = method.getRequest();

		String slideContext = request.getContextPath();
    	String requestUri = request.getRequestURI();
    	requestUri = requestUri.substring(slideContext.length());
    	
    	if (!match(requestUri,quotaPath)) {
    		Domain.log("put:requestUri "+requestUri+" does not match with the path "+quotaPath+" >return", LOG_CHANNEL, Logger.DEBUG);
    		return;
    	}// if (!match(requestUri,quotaPath)) {
    	
		Domain.log("deleteBeforeDelete:slideContext="+slideContext, LOG_CHANNEL, Logger.DEBUG);
		Domain.log("deleteBeforeDelete:requestUri="+requestUri, LOG_CHANNEL, Logger.DEBUG);
    	
    	try {
    		QuotaElement quotaElement = new QuotaElement(requestUri, method, QuotaConstants.CONTENT_LENGTH_IN_NRD);
    		String tmpCurrent = quotaElement.getContentLength();
    		tableOfResourceLength.put(requestUri, new ResourceLengthElement(requestUri, tmpCurrent));
    		Domain.log("deleteBeforeDelete:caching "+requestUri+" - contentLength="+tmpCurrent, LOG_CHANNEL, Logger.DEBUG);
    	} catch (IOException e) {
			throw new VetoException("Error parsing the request");
		    // TODO
    	} catch (AccessDeniedException e) {
//			 what should be done here ?
		} catch (LinkedObjectNotFoundException e) {
//			 what should be done here ?
		} catch (RevisionDescriptorNotFoundException e) {
//			 what should be done here ?
		} catch (ObjectLockedException e) {
//			 what should be done here ?
		} catch (ObjectNotFoundException e) {
//			 what should be done here ?
		} catch (ServiceAccessException e) {
//			 what should be done here ?
		} catch (VetoException e) {
//			 what should be done here ?
		}
		
	}// deleteBeforeDelete
	
	
	/**
	 * Called after the resource deletion
	 * - get the resource content lenght saved in the deleteBeforeDelete method
	 * - update resource quota MD
	 */
	public void deleteAfterDelete(DetailedWebdavEvent event) throws VetoException {
		
		Domain.log("deleteAfterDelete", LOG_CHANNEL, Logger.DEBUG);
		
		AbstractWebdavMethod method = (AbstractWebdavMethod)event.getSource();
		HttpServletRequest request = method.getRequest();

		String slideContext = request.getContextPath();
    	String requestUri = request.getRequestURI();
    	requestUri = requestUri.substring(slideContext.length());
    	
    	if (!match(requestUri,quotaPath)) {
    		Domain.log("put:requestUri "+requestUri+" does not match with the path "+quotaPath+" >return", LOG_CHANNEL, Logger.DEBUG);
    		return;
    	}// if (!match(requestUri,quotaPath)) {
    	
		Domain.log("deleteAfterDelete:slideContext="+slideContext, LOG_CHANNEL, Logger.DEBUG);
		Domain.log("deleteAfterDelete:requestUri="+requestUri, LOG_CHANNEL, Logger.DEBUG);

    	try {   		
    		String tmpCurrent = ((ResourceLengthElement)(tableOfResourceLength.get(requestUri))).getContentLength();
    		QuotaElement quotaElement = new QuotaElement(requestUri, method, tmpCurrent);
    		Domain.log("deleteAfterDelete:updating quota metadata for "+requestUri, LOG_CHANNEL, Logger.DEBUG);
    		quotaElement.updateQuotaMetadata(QuotaConstants.SUBTRACT_QUOTA_USED_BYTES, true);
    		Domain.log("deleteAfterDelete:removing entry "+requestUri+" from hashtable", LOG_CHANNEL, Logger.DEBUG);
    		tableOfResourceLength.remove(requestUri);
    	} catch (ObjectNotFoundException e) {
//    		 what should be done here ?
		} catch (AccessDeniedException e) {
//			 what should be done here ?
		} catch (LinkedObjectNotFoundException e) {
//			 what should be done here ?
		} catch (ObjectLockedException e) {
//			 what should be done here ?
		} catch (ServiceAccessException e) {
//			 what should be done here ?
		} catch (RevisionDescriptorNotFoundException e) {
//			 what should be done here ?
		} catch (RevisionNotFoundException e) {
//			 what should be done here ?
		} catch (VetoException e) {
//			 what should be done here ?
		}
		
	}// deleteAfterDelete
	
	
	/**
	 * Called after the resource is put
	 * - get the resource original content lenght (saved in the put method - if the resource already exist)
	 * - get the resource content lenght in the NRD
	 * - update resource quota MD
	 */
	public void putAfter(WebdavEvent event) throws VetoException {
		
		Domain.log("putAfter", LOG_CHANNEL, Logger.DEBUG);
		
		AbstractWebdavMethod method = (AbstractWebdavMethod)event.getSource();
		HttpServletRequest request = method.getRequest();

		String slideContext = request.getContextPath();
    	String requestUri = request.getRequestURI();
    	requestUri = requestUri.substring(slideContext.length());
    	
    	if (!match(requestUri,quotaPath)) {
    		Domain.log("put:requestUri "+requestUri+" does not match with the path "+quotaPath+" >return", LOG_CHANNEL, Logger.DEBUG);
    		return;
    	}// if (!match(requestUri,quotaPath)) {
    	
		Domain.log("putAfter:slideContext="+slideContext, LOG_CHANNEL, Logger.DEBUG);
		Domain.log("putAfter:requestUri="+requestUri, LOG_CHANNEL, Logger.DEBUG);
    	
    	try {
    		// trying to find the resource in the cache
    		Domain.log("putAfter:trying to find resource "+requestUri+" in the cache", LOG_CHANNEL, Logger.DEBUG);
    		int originalResourceContentLength = 0;
    		if (tableOfResourceLength.containsKey(requestUri)) {
    			String tmp = ((ResourceLengthElement)tableOfResourceLength.get(requestUri)).getContentLength();
    			originalResourceContentLength = Integer.parseInt(tmp);
    			Domain.log("putAfter:resource "+requestUri+" found in the cache - originalResourceContentLength="+originalResourceContentLength, LOG_CHANNEL, Logger.DEBUG);
    		}// if (tableOfResourceLength.containsKey(requestUri))
    			
    		QuotaElement quotaElement = new QuotaElement(requestUri, method, QuotaConstants.CONTENT_LENGTH_IN_NRD);
    		int contentLength = Integer.parseInt(quotaElement.getContentLength());
    		quotaElement = new QuotaElement(requestUri, method, String.valueOf(contentLength-originalResourceContentLength));
    		
    		Domain.log("putAfter:updating quota metadata for "+requestUri, LOG_CHANNEL, Logger.DEBUG);
    		quotaElement.updateQuotaMetadata(QuotaConstants.ADD_QUOTA_USED_BYTES, true);
    		
    		tableOfResourceLength.remove(requestUri); // can not be present
    	} catch (IOException e) {
			throw new VetoException("Error parsing the request");
			// TODO
    	} catch (ObjectNotFoundException e) {
//    		 what should be done here ?
		} catch (AccessDeniedException e) {
//   		 what should be done here ?
		} catch (LinkedObjectNotFoundException e) {
//   		 what should be done here ?
		} catch (ObjectLockedException e) {
//   		 what should be done here ?
		} catch (ServiceAccessException e) {
//   		 what should be done here ?
		} catch (RevisionDescriptorNotFoundException e) {
//   		 what should be done here ?
		} catch (RevisionNotFoundException e) {
//   		 what should be done here ?
		} catch (VetoException e) {
//   		 what should be done here ?
		}
		
	}// putAfter


	/**
	 * Called after the resource is copied
	 * - get the resource content lenght in the NRD
	 * - update resource quota MD
	 */
	public void copyAfterCopy(DetailedWebdavEvent event) throws VetoException {

		Domain.log("copyAfterCopy", LOG_CHANNEL, Logger.DEBUG);
	
		AbstractWebdavMethod method = (AbstractWebdavMethod)event.getSource();
		SlideToken slideToken = method.getSlideToken();
		HttpServletRequest request = method.getRequest();

		String destinationUri = event.getDestinationUri();
		
		if (!match(destinationUri,quotaPath)) {
    		Domain.log("put:destinationUri "+destinationUri+" does not match with the path "+quotaPath+" >return", LOG_CHANNEL, Logger.DEBUG);
    		return;
    	}// if (!match(requestUri,quotaPath)) {
		
		Domain.log("copyAfterCopy:destinationUri="+destinationUri, LOG_CHANNEL, Logger.DEBUG);
    	
    	try {
    		QuotaElement quotaElement = new QuotaElement(destinationUri, method, QuotaConstants.CONTENT_LENGTH_IN_NRD);
    		Domain.log("copyAfterCopy:updating quota metadata for "+destinationUri, LOG_CHANNEL, Logger.DEBUG);
    		quotaElement.updateQuotaMetadata(QuotaConstants.ADD_QUOTA_USED_BYTES, true);
    	} catch (IOException e) {
			throw new VetoException("Error parsing the request");
			// TODO
    	} catch (ObjectNotFoundException e) {
//  		 what should be done here ?
		} catch (AccessDeniedException e) {
//  		 what should be done here ?
		} catch (LinkedObjectNotFoundException e) {
//  		 what should be done here ?
		} catch (ObjectLockedException e) {
//  		 what should be done here ?
		} catch (ServiceAccessException e) {
//  		 what should be done here ?
		} catch (RevisionDescriptorNotFoundException e) {
//  		 what should be done here ?
		} catch (RevisionNotFoundException e) {
//  		 what should be done here ?
		} catch (VetoException e) {
//  		 what should be done here ?
		}
		
	}
	
	
	/**
	 * Called after the resource deletion
	 * - get the resource content lenght saved in the copyBeforeDelete method
	 * - update resource quota MD
	 */
	public void copyAfterDelete(DetailedWebdavEvent event) throws VetoException {
		
		Domain.log("copyAfterDelete", LOG_CHANNEL, Logger.DEBUG);
		
		AbstractWebdavMethod method = (AbstractWebdavMethod)event.getSource();
		SlideToken slideToken = method.getSlideToken();
		HttpServletRequest request = method.getRequest();

		String destinationUri = event.getDestinationUri();
		
		if (!match(destinationUri,quotaPath)) {
    		Domain.log("put:destinationUri "+destinationUri+" does not match with the path "+quotaPath+" >return", LOG_CHANNEL, Logger.DEBUG);
    		return;
    	}// if (!match(requestUri,quotaPath)) {
		
		Domain.log("copyAfterDelete:destinationUri="+destinationUri, LOG_CHANNEL, Logger.DEBUG);

    	try {   		
    		String tmpCurrent = ((ResourceLengthElement)(tableOfResourceLength.get(destinationUri))).getContentLength();
    		QuotaElement quotaElement = new QuotaElement(destinationUri, method, tmpCurrent);
    		Domain.log("copyAfterDelete:updating quota metadata for "+destinationUri, LOG_CHANNEL, Logger.DEBUG);
    		quotaElement.updateQuotaMetadata(QuotaConstants.SUBTRACT_QUOTA_USED_BYTES, true);
    		Domain.log("copyAfterDelete:removing entry "+destinationUri+" from hashtable", LOG_CHANNEL, Logger.DEBUG);
    		tableOfResourceLength.remove(destinationUri);
    	} catch (ObjectNotFoundException e) {
// 		 what should be done here ?
		} catch (AccessDeniedException e) {
// 		 what should be done here ?
		} catch (LinkedObjectNotFoundException e) {
// 		 what should be done here ?
		} catch (ObjectLockedException e) {
// 		 what should be done here ?
		} catch (ServiceAccessException e) {
// 		 what should be done here ?
		} catch (RevisionDescriptorNotFoundException e) {
// 		 what should be done here ?
		} catch (RevisionNotFoundException e) {
// 		 what should be done here ?
		} catch (VetoException e) {
// 		 what should be done here ?
		}

	}
	
	
	/**
	 * Called before a resource is about to be copied
	 * - throw a 507 error if the quota will be exceeded while copying the resource
	 */
	public void copyBeforeCopy(DetailedWebdavEvent event) throws VetoException {
		
		Domain.log("copyBeforeCopy", LOG_CHANNEL, Logger.DEBUG);
		
		AbstractWebdavMethod method = (AbstractWebdavMethod)event.getSource();
		SlideToken slideToken = method.getSlideToken();
		HttpServletRequest request = method.getRequest();

		String sourceUri = event.getSourceUri();
		String destinationUri = event.getDestinationUri();
		
		if (!match(destinationUri,quotaPath)) {
    		Domain.log("put:destinationUri "+destinationUri+" does not match with the path "+quotaPath+" >return", LOG_CHANNEL, Logger.DEBUG);
    		return;
    	}// if (!match(requestUri,quotaPath)) {
		
		Domain.log("copyBeforeCopy:sourceUri="+sourceUri, LOG_CHANNEL, Logger.DEBUG);
		Domain.log("copyBeforeCopy:destinationUri="+destinationUri, LOG_CHANNEL, Logger.DEBUG);
		
    	try {

    		QuotaElement quotaElementSource = new QuotaElement(sourceUri, method, QuotaConstants.CONTENT_LENGTH_IN_NRD);
    		String sourceContentLength = quotaElementSource.getContentLength();
    		QuotaElement quotaElementDestination = new QuotaElement(destinationUri, method, sourceContentLength);
    		
    		quotaElementDestination.initStorageAction();  		

    		if (quotaElementDestination.hasQuota()) {
    			if (quotaElementDestination.quotaExceeded()) {
    				Domain.log("copyBeforeCopy:quota exceeded for "+destinationUri, LOG_CHANNEL, Logger.INFO);
    				// getting the connected user
    				String connectedUser = slideToken.getCredentialsToken().getPrincipal().getName();
    				
    				// throw a VetoException
    				InsufficientStorageException insufficientStorageException = new InsufficientStorageException(destinationUri, connectedUser, QuotaConstants.QUOTA_EXCEEDED);
    				VetoException vetoException = new VetoException(QuotaConstants.QUOTA_EXCEEDED);
    				vetoException.initCause(insufficientStorageException);
    				throw vetoException;
    			}// (quotaElement.quotaExceeded())
    			else Domain.log("copyBeforeCopy:quota not exceeded for "+destinationUri, LOG_CHANNEL, Logger.DEBUG);
    		}// if (quotaElement.hasQuota())
    		else Domain.log("copyBeforeCopy:no quota for "+destinationUri, LOG_CHANNEL, Logger.DEBUG);
    	
    	} catch (IOException e) {
			throw new VetoException("Error parsing the request");
			// TODO
    	} catch (ObjectNotFoundException e) {
//    		 what should be done here ?
		} catch (AccessDeniedException e) {
//	 		 what should be done here ?
		} catch (LinkedObjectNotFoundException e) {
//	 		 what should be done here ?
		} catch (ObjectLockedException e) {
//	 		 what should be done here ?
		} catch (ServiceAccessException e) {
//	 		 what should be done here ?
		} catch (RevisionDescriptorNotFoundException e) {
//	 		 what should be done here ?
		}
		
		// in case of security problems...
//		SlideToken systemToken = new SlideTokenWrapper(slideToken);
//		systemToken.setForceSecurity(false);
//		systemToken.setForceLock(false); 
		
	}
	
	
	/**
	 * Called before a resource is about to be deleted
	 * - save the resource content lenght for the copyAfterDelete method
	 */
	public void copyBeforeDelete(DetailedWebdavEvent event) throws VetoException {
		Domain.log("copyBeforeDelete", LOG_CHANNEL, Logger.DEBUG);
		
		AbstractWebdavMethod method = (AbstractWebdavMethod)event.getSource();
		SlideToken slideToken = method.getSlideToken();
		HttpServletRequest request = method.getRequest();

		String destinationUri = event.getDestinationUri();
		
		if (!match(destinationUri,quotaPath)) {
    		Domain.log("put:destinationUri "+destinationUri+" does not match with the path "+quotaPath+" >return", LOG_CHANNEL, Logger.DEBUG);
    		return;
    	}// if (!match(requestUri,quotaPath)) {
		
		Domain.log("copyBeforeDelete:destinationUri="+destinationUri, LOG_CHANNEL, Logger.DEBUG);
		
    	try {
    		QuotaElement quotaElement = new QuotaElement(destinationUri, method, QuotaConstants.CONTENT_LENGTH_IN_NRD);
    		String tmpCurrent = quotaElement.getContentLength();
    		tableOfResourceLength.put(destinationUri, new ResourceLengthElement(destinationUri, tmpCurrent));
    		Domain.log("copyBeforeDelete:caching "+destinationUri+" - contentLength="+tmpCurrent, LOG_CHANNEL, Logger.DEBUG);
    	} catch (IOException e) {
			throw new VetoException("Error parsing the request");
			// TODO
    	} catch (AccessDeniedException e) {
//	 		 what should be done here ?
		} catch (LinkedObjectNotFoundException e) {
//	 		 what should be done here ?
		} catch (RevisionDescriptorNotFoundException e) {
//	 		 what should be done here ?
		} catch (ObjectLockedException e) {
//	 		 what should be done here ?
		} catch (ObjectNotFoundException e) {
//	 		 what should be done here ?
		} catch (ServiceAccessException e) {
//	 		 what should be done here ?
		} catch (VetoException e) {
//	 		 what should be done here ?
		}
	}
	
	
	/**
	 * Called after the resource is copied
	 * - get the resource content lenght in the NRD
	 * - update resource quota MD
	 */
	public void moveAfterCopy(DetailedWebdavEvent event) throws VetoException {
		
		Domain.log("moveAfterCopy", LOG_CHANNEL, Logger.DEBUG);
		
		AbstractWebdavMethod method = (AbstractWebdavMethod)event.getSource();
		SlideToken slideToken = method.getSlideToken();
		HttpServletRequest request = method.getRequest();

		String destinationUri = event.getDestinationUri();
		
		if (!match(destinationUri,quotaPath)) {
    		Domain.log("put:destinationUri "+destinationUri+" does not match with the path "+quotaPath+" >return", LOG_CHANNEL, Logger.DEBUG);
    		return;
    	}// if (!match(requestUri,quotaPath)) {
		
		Domain.log("moveAfterCopy:destinationUri="+destinationUri, LOG_CHANNEL, Logger.DEBUG);
    	
    	try {
    		QuotaElement quotaElement = new QuotaElement(destinationUri, method, QuotaConstants.CONTENT_LENGTH_IN_NRD);
    		Domain.log("moveAfterCopy:updating quota metadata for "+destinationUri, LOG_CHANNEL, Logger.DEBUG);
    		quotaElement.updateQuotaMetadata(QuotaConstants.ADD_QUOTA_USED_BYTES, true);
    	} catch (IOException e) {
			throw new VetoException("Error parsing the request");
			// TODO
    	} catch (ObjectNotFoundException e) {
//	 		 what should be done here ?
		} catch (AccessDeniedException e) {
//	 		 what should be done here ?
		} catch (LinkedObjectNotFoundException e) {
//	 		 what should be done here ?
		} catch (ObjectLockedException e) {
//	 		 what should be done here ?
		} catch (ServiceAccessException e) {
//	 		 what should be done here ?
		} catch (RevisionDescriptorNotFoundException e) {
//	 		 what should be done here ?
		} catch (RevisionNotFoundException e) {
//	 		 what should be done here ?
		} catch (VetoException e) {
//	 		 what should be done here ?
		}
		
	}
	
	
	/**
	 * Called after the resource deletion
	 * - get the resource content lenght saved in the moveBeforeDelete method
	 * - update resource quota MD
	 */
	public void moveAfterDelete(DetailedWebdavEvent event) throws VetoException {
		
		Domain.log("moveAfterDelete", LOG_CHANNEL, Logger.DEBUG);
		
		Domain.log("moveAfterDelete", LOG_CHANNEL, Logger.DEBUG);
		
		AbstractWebdavMethod method = (AbstractWebdavMethod)event.getSource();
		SlideToken slideToken = method.getSlideToken();
		HttpServletRequest request = method.getRequest();

		String destinationUri = event.getDestinationUri();
		
		if (!match(destinationUri,quotaPath)) {
    		Domain.log("put:destinationUri "+destinationUri+" does not match with the path "+quotaPath+" >return", LOG_CHANNEL, Logger.DEBUG);
    		return;
    	}// if (!match(requestUri,quotaPath)) {
		
		Domain.log("moveAfterDelete:destinationUri="+destinationUri, LOG_CHANNEL, Logger.DEBUG);

    	try {   		
    		String tmpCurrent = ((ResourceLengthElement)(tableOfResourceLength.get(destinationUri))).getContentLength();
    		QuotaElement quotaElement = new QuotaElement(destinationUri, method, tmpCurrent);
    		Domain.log("moveAfterDelete:updating quota metadata for "+destinationUri, LOG_CHANNEL, Logger.DEBUG);
    		quotaElement.updateQuotaMetadata(QuotaConstants.SUBTRACT_QUOTA_USED_BYTES, true);
    		Domain.log("moveAfterDelete:removing entry "+destinationUri+" from hashtable", LOG_CHANNEL, Logger.DEBUG);
    		tableOfResourceLength.remove(destinationUri);
    	} catch (ObjectNotFoundException e) {
//	 		 what should be done here ?
		} catch (AccessDeniedException e) {
//	 		 what should be done here ?
		} catch (LinkedObjectNotFoundException e) {
//	 		 what should be done here ?
		} catch (ObjectLockedException e) {
//	 		 what should be done here ?
		} catch (ServiceAccessException e) {
//	 		 what should be done here ?
		} catch (RevisionDescriptorNotFoundException e) {
//	 		 what should be done here ?
		} catch (RevisionNotFoundException e) {
//	 		 what should be done here ?
		} catch (VetoException e) {
//	 		 what should be done here ?
		}
		
	}
	
	
	/**
	 * Called before a resource is about to be moved
	 * - throw a 507 error if the quota will be exceeded while copying the resource
	 */
	public void moveBeforeCopy(DetailedWebdavEvent event) throws VetoException {
		
		Domain.log("moveBeforeCopy", LOG_CHANNEL, Logger.DEBUG);
		
	
		AbstractWebdavMethod method = (AbstractWebdavMethod)event.getSource();
		SlideToken slideToken = method.getSlideToken();
		HttpServletRequest request = method.getRequest();

		String sourceUri = event.getSourceUri();
		String destinationUri = event.getDestinationUri();
		
		if (!match(destinationUri,quotaPath)) {
    		Domain.log("put:destinationUri "+destinationUri+" does not match with the path "+quotaPath+" >return", LOG_CHANNEL, Logger.DEBUG);
    		return;
    	}// if (!match(requestUri,quotaPath)) {
		
		Domain.log("moveBeforeCopy:sourceUri="+sourceUri, LOG_CHANNEL, Logger.DEBUG);
		Domain.log("moveBeforeCopy:destinationUri="+destinationUri, LOG_CHANNEL, Logger.DEBUG);
		
    	try {

    		QuotaElement quotaElementSource = new QuotaElement(sourceUri, method, QuotaConstants.CONTENT_LENGTH_IN_NRD);
    		String sourceContentLength = quotaElementSource.getContentLength();
    		QuotaElement quotaElementDestination = new QuotaElement(destinationUri, method, sourceContentLength);
    		
    		quotaElementDestination.initStorageAction();  		

    		if (quotaElementDestination.hasQuota()) {
    			if (quotaElementDestination.quotaExceeded()) {
    				Domain.log("moveBeforeCopy:quota exceeded for "+destinationUri, LOG_CHANNEL, Logger.INFO);
    				// getting the connected user
    				String connectedUser = slideToken.getCredentialsToken().getPrincipal().getName();
    				
    				// throw a VetoException
    				InsufficientStorageException insufficientStorageException = new InsufficientStorageException(destinationUri, connectedUser, QuotaConstants.QUOTA_EXCEEDED);
    				VetoException vetoException = new VetoException(QuotaConstants.QUOTA_EXCEEDED);
    				vetoException.initCause(insufficientStorageException);
    				throw vetoException;
    			}// (quotaElement.quotaExceeded())
    			else Domain.log("moveBeforeCopy:quota not exceeded for "+destinationUri, LOG_CHANNEL, Logger.DEBUG);
    		}// if (quotaElement.hasQuota())
    		else Domain.log("moveBeforeCopy:no quota for "+destinationUri, LOG_CHANNEL, Logger.DEBUG);
    	
    	} catch (IOException e) {
			throw new VetoException("Error parsing the request");
			// TODO
    	} catch (ObjectNotFoundException e) {
//	 		 what should be done here ?
		} catch (AccessDeniedException e) {
//	 		 what should be done here ?
		} catch (LinkedObjectNotFoundException e) {
//	 		 what should be done here ?
		} catch (ObjectLockedException e) {
//	 		 what should be done here ?
		} catch (ServiceAccessException e) {
//	 		 what should be done here ?
		} catch (RevisionDescriptorNotFoundException e) {
//	 		 what should be done here ?
		}
		
		// in case of security problems...
//		SlideToken systemToken = new SlideTokenWrapper(slideToken);
//		systemToken.setForceSecurity(false);
//		systemToken.setForceLock(false); 
		
	}
	
	
	/**
	 * Called before a resource is about to be moved
	 * - save the resource content lenght for the moveAfterDelete method
	 */
	public void moveBeforeDelete(DetailedWebdavEvent event) throws VetoException {
		Domain.log("moveBeforeDelete", LOG_CHANNEL, Logger.DEBUG);
		
		AbstractWebdavMethod method = (AbstractWebdavMethod)event.getSource();
		SlideToken slideToken = method.getSlideToken();
		HttpServletRequest request = method.getRequest();

		String destinationUri = event.getDestinationUri();
		
		if (!match(destinationUri,quotaPath)) {
    		Domain.log("put:destinationUri "+destinationUri+" does not match with the path "+quotaPath+" >return", LOG_CHANNEL, Logger.DEBUG);
    		return;
    	}// if (!match(requestUri,quotaPath)) {
		
		Domain.log("moveBeforeDelete:destinationUri="+destinationUri, LOG_CHANNEL, Logger.DEBUG);
		
    	try {
    		QuotaElement quotaElement = new QuotaElement(destinationUri, method, QuotaConstants.CONTENT_LENGTH_IN_NRD);
    		String tmpCurrent = quotaElement.getContentLength();
    		tableOfResourceLength.put(destinationUri, new ResourceLengthElement(destinationUri, tmpCurrent));
    		Domain.log("moveBeforeDelete:caching "+destinationUri+" - contentLength="+tmpCurrent, LOG_CHANNEL, Logger.DEBUG);
		
    	} catch (IOException e) {
			throw new VetoException("Error parsing the request");
			// TODO
    	} catch (AccessDeniedException e) {
//	 		 what should be done here ?
		} catch (LinkedObjectNotFoundException e) {
//	 		 what should be done here ?
		} catch (RevisionDescriptorNotFoundException e) {
//	 		 what should be done here ?
		} catch (ObjectLockedException e) {
//	 		 what should be done here ?
		} catch (ObjectNotFoundException e) {
//	 		 what should be done here ?
		} catch (ServiceAccessException e) {
//	 		 what should be done here ?
		} catch (VetoException e) {
//	 		 what should be done here ?
		}
	}
	
	
	/**
	 * Called before a resource is about to be put
	 * - check if the resource already exist and then save its content lenght
	 * - throw a 507 error if the quota will be exceeded while puting the resource
	 */
	public void put(WebdavEvent event) throws VetoException {
		
		Domain.log("put", LOG_CHANNEL, Logger.DEBUG);

		AbstractWebdavMethod method = (AbstractWebdavMethod)event.getSource();
		SlideToken slideToken = method.getSlideToken();
		HttpServletRequest request = method.getRequest();

		String slideContext = request.getContextPath();
    	String requestUri = request.getRequestURI();
    	requestUri = requestUri.substring(slideContext.length());
    	
    	if (!match(requestUri,quotaPath)) {
    		Domain.log("put:requestUri "+requestUri+" does not match with the path "+quotaPath+" >return", LOG_CHANNEL, Logger.DEBUG);
    		return;
    	}// if (!match(requestUri,quotaPath)) {
    	
		Domain.log("put:slideContext="+slideContext, LOG_CHANNEL, Logger.DEBUG);
		Domain.log("put:requestUri="+requestUri, LOG_CHANNEL, Logger.DEBUG);
	
		try {

    		// check if the resource already exists (required only for a put method)
    		boolean resourceExists = false;
    		String originalResourceContentLength = null;
    		
    		Domain.log("put:checking if the resource already exists", LOG_CHANNEL, Logger.DEBUG);
    		try {
    			Content content = method.getContent();
				NodeRevisionDescriptors nrds = content.retrieve(slideToken, requestUri);
				NodeRevisionDescriptor nrd = content.retrieve(slideToken, nrds);
				originalResourceContentLength = (nrd.getProperty(QuotaConstants.NRD_CONTENT_LENGTH, QuotaConstants.NAMESPACE_DAV).getValue()).toString();
				Domain.log("put:resource "+requestUri+" already exists - originalResourceContentLength="+originalResourceContentLength, LOG_CHANNEL, Logger.DEBUG);
				resourceExists = true;
			} catch (ObjectNotFoundException e) {
				Domain.log("put:resource "+requestUri+" does NOT exists", LOG_CHANNEL, Logger.DEBUG);
			}
    		
    		QuotaElement quotaElement;
			quotaElement = new QuotaElement(requestUri, method, QuotaConstants.CONTENT_LENGTH_IN_REQUEST);
			quotaElement.initStorageAction();  		

    		if (quotaElement.hasQuota()) {
    			if (quotaElement.quotaExceeded()) {
    				Domain.log("put:quota exceeded for "+requestUri, LOG_CHANNEL, Logger.INFO);
    				// getting the connected user
    				String connectedUser = slideToken.getCredentialsToken().getPrincipal().getName();
    				
    				// throw a VetoException
    				InsufficientStorageException insufficientStorageException = new InsufficientStorageException(requestUri, connectedUser, QuotaConstants.QUOTA_EXCEEDED);
    				VetoException vetoException = new VetoException(QuotaConstants.QUOTA_EXCEEDED);
    				vetoException.initCause(insufficientStorageException);
    				throw vetoException;
    			}// (quotaElement.quotaExceeded())
    			else {
    				Domain.log("put:quota not exceeded for "+requestUri, LOG_CHANNEL, Logger.DEBUG);
    				
    				// if the resource already exist then caching its content length
    	    		if (resourceExists) {
    	    			tableOfResourceLength.put(requestUri, new ResourceLengthElement(requestUri, originalResourceContentLength));
    	        		Domain.log("copyBeforeDelete:caching "+requestUri+" - originalResourceContentLength="+originalResourceContentLength, LOG_CHANNEL, Logger.DEBUG);
    	    		}// if (resourceExists)
    	    		
    			}// else (quotaElement.quotaExceeded())
    		}// if (quotaElement.hasQuota())
    		else Domain.log("put:no quota for "+requestUri, LOG_CHANNEL, Logger.DEBUG);
    		
		} catch (IOException e) {
			throw new VetoException("Error parsing the request");
			// TODO
    	} catch (ObjectNotFoundException e) {
//	 		 what should be done here ?
		} catch (AccessDeniedException e) {
//	 		 what should be done here ?
		} catch (LinkedObjectNotFoundException e) {
//	 		 what should be done here ?
		} catch (ObjectLockedException e) {
//	 		 what should be done here ?
		} catch (ServiceAccessException e) {
//	 		 what should be done here ?
		} catch (RevisionDescriptorNotFoundException e) {
//	 		 what should be done here ?
		}
		
		// in case of security problems...
//		SlideToken systemToken = new SlideTokenWrapper(slideToken);
//		systemToken.setForceSecurity(false);
//		systemToken.setForceLock(false); 
		
	}// put


	public void retrieve(ContentEvent event) throws VetoException {
	}

	public void store(ContentEvent event) throws VetoException {
	}

	public void create(ContentEvent event) throws VetoException {
	}

	public void remove(ContentEvent event) throws VetoException {
	}

	public void fork(ContentEvent event) throws VetoException {
	}

	public void merge(ContentEvent event) throws VetoException {
	}

	public void configure(Configuration configuration) throws ConfigurationException {
		quotaPath = configuration.getConfiguration("path").getValue();
		Domain.log("configure:path="+quotaPath, LOG_CHANNEL, Logger.DEBUG);
	}
	
}// QuotaListener
