/* * $Id: WebdavLocalResource.java,v 1.5 2007/08/20 14:41:03 valdas Exp $ * Created on 11.10.2005 in project com.idega.slide * * Copyright (C) 2005 Idega Software hf. All Rights Reserved. * * This software is the proprietary information of Idega hf. * Use is subject to license terms. */ package com.idega.slide.util; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.List; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.HttpURL; import org.apache.slide.content.NodeProperty; import org.apache.slide.content.NodeRevisionDescriptor; import org.apache.slide.content.RevisionDescriptorNotFoundException; import org.apache.slide.security.NodePermission; import org.apache.slide.structure.ObjectNotFoundException; import org.apache.webdav.lib.Ace; import org.apache.webdav.lib.Property; import org.apache.webdav.lib.PropertyName; import org.apache.webdav.lib.WebdavResource; import org.apache.webdav.lib.WebdavResources; import org.apache.webdav.lib.properties.AclProperty; import org.apache.webdav.lib.properties.ResourceTypeProperty; import org.apache.webdav.lib.util.WebdavStatus; import org.springframework.beans.factory.annotation.Autowired; import org.w3c.dom.Document; import org.w3c.dom.Element; import com.idega.slide.business.IWSimpleSlideService; import com.idega.util.CoreConstants; import com.idega.util.ListUtil; import com.idega.util.StringHandler; import com.idega.util.StringUtil; import com.idega.util.expression.ELUtil; import com.idega.util.xml.XmlUtil; /** * <p> * This class is an extension of the standard WebdavResource to perform some common * operations locally (in the jvm) instead of going through http when communicating with * the built in WebDav server. This class is experimental only. * </p> * Last modified: $Date: 2007/08/20 14:41:03 $ by $Author: valdas $ * * @author <a href="mailto:tryggvil@idega.com">tryggvil</a> * @version $Revision: 1.5 $ */ public class WebdavLocalResource extends WebdavExtendedResource { private static final Logger LOGGER = Logger.getLogger(WebdavLocalResource.class.getName()); private Element emptyElement, collectionElement; private String displayName, name, contentType; private Long length; private Boolean collection, exists; private Enumeration<LocalResponse> properties; private WebdavResources children; @Autowired private IWSimpleSlideService slideAPI; /** * @param client - {@link HttpClient} */ public WebdavLocalResource(HttpClient client) { super(client); } /** * Create a new WebdavResource object (as a seperate method so that it can be overridden by subclasses.) * @param client HttpClient to be used by this webdavresource. * @return A new WebdavResource object. */ @Override protected WebdavResource createWebdavResource(HttpClient client) { WebdavResource resource = new WebdavLocalResource(client); resource.setCredentials(this.hostCredentials); return resource; } @Override public void setHttpURL(HttpURL httpURL) throws HttpException, IOException { this.httpURL = httpURL; } /** * Set all properties for this resource. * * @param depth The depth */ @Override protected void setAllProp(int depth) throws HttpException, IOException { @SuppressWarnings("unchecked") Enumeration<LocalResponse> responses = propfindMethod(depth); setWebdavProperties(responses); } @Override public Enumeration<LocalResponse> propfindMethod(String path, int depth) throws HttpException, IOException { return propfindMethod(path,depth,null); } @Override public Enumeration<LocalResponse> propfindMethod(String path, int depth, @SuppressWarnings("rawtypes") Vector presetProperties) throws HttpException, IOException { if (properties == null) { String resourcePath = getPath(); if (resourcePath.startsWith(CoreConstants.WEBDAV_SERVLET_URI)) { resourcePath = resourcePath.substring(CoreConstants.WEBDAV_SERVLET_URI.length()); } try { if (!getSlideAPI().checkExistance(resourcePath)) { return Collections.enumeration(new ArrayList<LocalResponse>()); } } catch (Exception e) {} try { NodeRevisionDescriptor rev = getSlideAPI().getRevisionDescriptor(resourcePath); properties = propfindMethod(rev); } catch (Exception e) { if (e instanceof ObjectNotFoundException) { getSlideAPI().deletetDefinitionFile(((ObjectNotFoundException) e).getObjectUri()); } else if (e instanceof RevisionDescriptorNotFoundException) { getSlideAPI().deletetDefinitionFile(((RevisionDescriptorNotFoundException) e).getObjectUri()); } } } return properties; } @SuppressWarnings("deprecation") private Enumeration<LocalResponse> propfindMethod(NodeRevisionDescriptor descriptor) throws HttpException, IOException { if (descriptor == null) { return null; } if (properties != null) { return properties; } try { Vector<LocalResponse> responses = new Vector<LocalResponse>(); LocalResponse response = new LocalResponse(); response.setHref(getPath()); responses.add(response); @SuppressWarnings("unchecked") List<NodeProperty> nodeProperties = Collections.list(descriptor.enumerateProperties()); List<Property> properties = new ArrayList<Property>(); for (NodeProperty p: nodeProperties) { String localName = p.getPropertyName().getName(); Property property = null; if (localName.equals(RESOURCETYPE)) { Object oValue = p.getValue(); String value = oValue == null ? null : oValue.toString(); Element element = null; if ("<collection/>".equals(value)) { element = getCollectionElement(); } else if (CoreConstants.EMPTY.equals(value)) { element = getEmptyElement(); } else { Document doc = XmlUtil.getDocumentBuilder().newDocument(); String namespace = p.getNamespace(); String tagName = p.getName(); element = doc.createElementNS(namespace, tagName); element.appendChild(doc.createTextNode(value)); } property = new ResourceTypeProperty(response, element); } else if (localName.equals(LOCKDISCOVERY)) { /*DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.newDocument(); Element element = doc.createElement("collection"); property = new LockDiscoveryProperty(response,element);*/ throw new RuntimeException("LockDiscoveryProperty not yet implemented for: " + getPath()); } else if (CREATIONDATE.equals(localName)) { setCreationDate((String) p.getValue()); } else if (GETLASTMODIFIED.equals(localName)) { setGetLastModified((String) p.getValue()); } else { LocalProperty lProperty = new LocalProperty(response); property = lProperty; lProperty.setName(p.getName()); lProperty.setNamespaceURI(p.getNamespace()); lProperty.setLocalName(p.getName()); Object oValue = p.getValue(); String value = oValue == null ? null : oValue.toString(); lProperty.setPropertyAsString(value); } if (property != null) { properties.add(property); } } if (!ListUtil.isEmpty(properties)) { response.setProperties(new Vector<Property>(properties)); } this.properties = responses.elements(); if (this.properties != null) { setProperties(3, 0); // Need to set basic properties } return this.properties; } catch (Exception e) { LOGGER.log(Level.WARNING, "Error getting properties for: " + getPath() + ": " + e.getMessage(), e); if (e instanceof ObjectNotFoundException) { getSlideAPI().deletetDefinitionFile(((ObjectNotFoundException) e).getObjectUri()); HttpException he = new HttpException("Resource on path: " + getPath() + " not found"); he.setReasonCode(WebdavStatus.SC_NOT_FOUND); throw he; } else if (e instanceof RevisionDescriptorNotFoundException) { getSlideAPI().deletetDefinitionFile(((RevisionDescriptorNotFoundException) e).getObjectUri()); } return null; } } private Enumeration<LocalResponse> propfindMethod() { try { return propfindMethod(getPath(), 1); } catch (Exception e) { LOGGER.log(Level.WARNING, "Error extracting properties for item: " + getPath(), e); } return null; } private Element getEmptyElement() { if (emptyElement == null) { Document doc = XmlUtil.getXMLBuilder().newDocument(); emptyElement = doc.createElementNS("DAV:", "resourcetype"); emptyElement.appendChild(doc.createTextNode(CoreConstants.EMPTY)); } return emptyElement; } private Element getCollectionElement() { if (collectionElement == null) { Document doc = XmlUtil.getXMLBuilder().newDocument(); collectionElement = doc.createElementNS("DAV:", "resourcetype"); collectionElement.appendChild(doc.createElementNS("DAV:", "collection")); } return collectionElement; } @Override public boolean putMethod(byte[] data) throws HttpException, IOException { return putMethod(httpURL.getPath(), data); } @Override public boolean putMethod(File file) throws HttpException, IOException { return putMethod(httpURL.getPath(), file); } @Override public boolean putMethod(InputStream is) throws HttpException, IOException { return putMethod(httpURL.getPath(), is); } @Override public boolean putMethod(String path, byte[] data) throws HttpException, IOException { return putMethod(path, new ByteArrayInputStream(data)); } @Override public boolean putMethod(String path, File file) throws HttpException, IOException { return putMethod(path, new FileInputStream(file)); } @Override public boolean putMethod(String path, InputStream is) throws HttpException, IOException { if (!getSlideAPI().setContent(path, is)) { return super.putMethod(path, is); } return Boolean.TRUE; } @Override public boolean putMethod(String path, String data) throws HttpException, IOException { try { return putMethod(path, StringHandler.getStreamFromString(data)); } catch (Exception e) { LOGGER.log(Level.WARNING, "Error writing data '".concat(data).concat("' to: ").concat(path), e); } return super.putMethod(path, data); } @Deprecated @Override /** * Use another method (like putMethod(String path, InputStream is)) to set content */ public boolean putMethod(String path, URL url) throws HttpException, IOException { return super.putMethod(path, url); } @Override public boolean putMethod(String data) throws HttpException, IOException { try { return putMethod(StringHandler.getStreamFromString(data)); } catch (Exception e) { LOGGER.log(Level.WARNING, "Error writing data '".concat(data).concat("' to: ").concat(httpURL.getPath()), e); } return super.putMethod(data); } @Deprecated @Override /** * Use another method (like putMethod(String path, InputStream is)) to set content */ public boolean putMethod(URL url) throws HttpException, IOException { return super.putMethod(url); } @Override public InputStream getMethodData() throws HttpException, IOException { return getMethodData(httpURL.getPath()); } @Override public InputStream getMethodData(String path) throws HttpException, IOException { InputStream stream = null; try { stream = getSlideAPI().getInputStream(path); } catch (Exception e) { LOGGER.log(Level.WARNING, "Error getting input stream from: ".concat(path), e); } if (stream == null) stream = super.getMethodData(path); return stream; } @Override public boolean exists() { if (exists == null) { try { exists = getSlideAPI().checkExistance(httpURL.getPath()); } catch (Exception e) { LOGGER.log(Level.WARNING, "Error checking if resource exists: " + this, e); } if (exists == null) { propfindMethod(); exists = super.exists(); } } return exists; } @Override public boolean getExistence() { return exists(); } @Override public AclProperty aclfindMethod() throws HttpException, IOException { return aclfindMethod(httpURL.getPath()); } @Override public AclProperty aclfindMethod(String path) throws HttpException, IOException { Enumeration<NodePermission> permissions = getSlideAPI().getPermissions(path); if (permissions == null || !permissions.hasMoreElements()) { return null; } return new LocalAclProperty(permissions); } @Override public boolean aclMethod(String path, Ace[] aces) throws HttpException, IOException { return getSlideAPI().setPermissions(path, aces); } @Override public boolean deleteMethod() throws HttpException, IOException { return deleteMethod(httpURL.getPath()); } @Override public boolean deleteMethod(String path) throws HttpException, IOException { if (!getSlideAPI().delete(path)) { return super.deleteMethod(path); } return Boolean.TRUE; } private IWSimpleSlideService getSlideAPI() { if (slideAPI == null) { ELUtil.getInstance().autowire(this); } return slideAPI; } @Override public boolean mkcolMethod() throws HttpException, IOException { return mkcolMethod(httpURL.getPath()); } @Override public boolean mkcolMethod(String path) throws HttpException, IOException { return getSlideAPI().createStructure(path); } @Override public long getGetContentLength() { if (length == null) { NodeRevisionDescriptor descriptor = getRevisionDescriptor(); length = descriptor == null ? super.getGetContentLength() : descriptor.getContentLength(); } return length; } @Override public String getGetContentType() { if (contentType == null) { NodeRevisionDescriptor descriptor = getRevisionDescriptor(); contentType = descriptor == null ? super.getGetContentType() : descriptor.getContentType(); } return contentType; } @Override public boolean isCollection() { if (collection == null) { NodeRevisionDescriptor descriptor = getRevisionDescriptor(); if (descriptor == null) { collection = super.isCollection(); } else { String resourceType = descriptor.getResourceType(); collection = !StringUtil.isEmpty(resourceType) && resourceType.indexOf("collection") != -1; } } return collection; } @Override public String getDisplayName() { if (displayName == null) { propfindMethod(); displayName = super.getDisplayName(); } return displayName; } @Override public String getName() { if (name == null) { propfindMethod(); name = super.getName(); } return name; } @Override public WebdavResources getChildResources() throws HttpException, IOException { if (children == null) { children = getSlideAPI().getResources(httpURL.getPath()); } return children; } private NodeRevisionDescriptor getRevisionDescriptor() { NodeRevisionDescriptor descriptor = null; try { descriptor = getSlideAPI().getRevisionDescriptor(httpURL.getPath()); } catch (Exception e) { LOGGER.log(Level.WARNING, "Error resolving if resource is a directory: " + httpURL, e); } if (descriptor != null && properties == null) { try { propfindMethod(descriptor); } catch (Exception e) { LOGGER.log(Level.WARNING, "Error extracting properties for item: " + getPath(), e); } } return descriptor; } @Override public boolean proppatchMethod(PropertyName propertyName, String propertyValue, boolean action) throws HttpException, IOException { if (propertyName == null) { return false; } try { NodeRevisionDescriptor descriptor = getRevisionDescriptor(); descriptor.setProperty(propertyName.getLocalName(), propertyName.getNamespaceURI(), propertyValue); return true; } catch (Exception e) { LOGGER.log(Level.WARNING, "Error setting property " + propertyName + " with value " + propertyValue + " for " + httpURL.getPath(), e); } return super.proppatchMethod(propertyName, propertyValue, action); } }