All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.jackrabbit.webdav.simple.ResourceConfig Maven / Gradle / Ivy

There is a newer version: 2.23.0-beta
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.jackrabbit.webdav.simple;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.jcr.Item;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.jackrabbit.server.io.CopyMoveHandler;
import org.apache.jackrabbit.server.io.CopyMoveManager;
import org.apache.jackrabbit.server.io.CopyMoveManagerImpl;
import org.apache.jackrabbit.server.io.DefaultIOManager;
import org.apache.jackrabbit.server.io.IOHandler;
import org.apache.jackrabbit.server.io.IOManager;
import org.apache.jackrabbit.server.io.PropertyHandler;
import org.apache.jackrabbit.server.io.PropertyManager;
import org.apache.jackrabbit.server.io.PropertyManagerImpl;
import org.apache.jackrabbit.webdav.xml.DomUtil;
import org.apache.jackrabbit.webdav.xml.ElementIterator;
import org.apache.jackrabbit.webdav.xml.Namespace;
import org.apache.tika.detect.Detector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;

/**
 * ResourceConfig...
 */
public class ResourceConfig {

    private static Logger log = LoggerFactory.getLogger(ResourceConfig.class);

    private static final String ELEMENT_IOMANAGER = "iomanager";
    private static final String ELEMENT_IOHANDLER = "iohandler";

    private static final String ELEMENT_PROPERTYMANAGER = "propertymanager";
    private static final String ELEMENT_PROPERTYHANDLER = "propertyhandler";

    private static final String ELEMENT_COPYMOVEMANAGER = "copymovemanager";
    private static final String ELEMENT_COPYMOVEHANDLER = "copymovehandler";

    private static final String ELEMENT_CLASS = "class";

    private static final String ELEMENT_PARAM = "param";
    private static final String ATTR_NAME = "name";
    private static final String ATTR_VALUE = "value";

    /**
     * Content type detector.
     */
    private final Detector detector;

    private ItemFilter itemFilter;
    private IOManager ioManager;
    private CopyMoveManager cmManager;
    private PropertyManager propManager;
    private String[] nodetypeNames = new String[0];
    private boolean collectionNames = false;

    public ResourceConfig(Detector detector) {
        this.detector = detector;
    }

    /**
     * Tries to parse the given xml configuration file.
     * The xml must match the following structure:
*
     * <!ELEMENT config (iomanager, propertymanager, (collection | noncollection)?, filter?, mimetypeproperties?) >
     * <!ELEMENT iomanager (class, iohandler*) >
     * <!ELEMENT iohandler (class) >
     * <!ELEMENT propertymanager (class, propertyhandler*) >
     * <!ELEMENT propertyhandler (class) >
     * <!ELEMENT collection (nodetypes) >
     * <!ELEMENT noncollection (nodetypes) >
     * <!ELEMENT filter (class, namespaces?, nodetypes?) >
     * <!ELEMENT class >
     *    <!ATTLIST class
     *      name  CDATA #REQUIRED
     *    >
     * <!ELEMENT namespaces (prefix|uri)* >
     * <!ELEMENT prefix (CDATA) >
     * <!ELEMENT uri (CDATA) >
     * <!ELEMENT nodetypes (nodetype)* >
     * <!ELEMENT nodetype (CDATA) >
     * <!ELEMENT mimetypeproperties (mimemapping*, defaultmimetype) >
     * <!ELEMENT mimemapping >
     *    <!ATTLIST mimemapping
     *      extension  CDATA #REQUIRED
     *      mimetype  CDATA #REQUIRED
     *    >
     * <!ELEMENT defaultmimetype (CDATA) >
     * 
*

* The <mimetypeproperties/> settings have been deprecated and will * be ignored with a warning. Instead you can use the * {@link SimpleWebdavServlet#INIT_PARAM_MIME_INFO mime-info} * servlet initialization parameter to customize the media type settings. * * @param configURL */ public void parse(URL configURL) { try { parse(configURL.openStream()); } catch (IOException e) { log.debug("Invalid resource configuration: " + e.getMessage()); } } /** * Parses the given input stream into the xml configuration file. * The xml must match the following structure:
*

     * <!ELEMENT config (iomanager, propertymanager, (collection | noncollection)?, filter?, mimetypeproperties?) >
     * <!ELEMENT iomanager (class, iohandler*) >
     * <!ELEMENT iohandler (class) >
     * <!ELEMENT propertymanager (class, propertyhandler*) >
     * <!ELEMENT propertyhandler (class) >
     * <!ELEMENT collection (nodetypes) >
     * <!ELEMENT noncollection (nodetypes) >
     * <!ELEMENT filter (class, namespaces?, nodetypes?) >
     * <!ELEMENT class >
     *    <!ATTLIST class
     *      name  CDATA #REQUIRED
     *    >
     * <!ELEMENT namespaces (prefix|uri)* >
     * <!ELEMENT prefix (CDATA) >
     * <!ELEMENT uri (CDATA) >
     * <!ELEMENT nodetypes (nodetype)* >
     * <!ELEMENT nodetype (CDATA) >
     * <!ELEMENT mimetypeproperties (mimemapping*, defaultmimetype) >
     * <!ELEMENT mimemapping >
     *    <!ATTLIST mimemapping
     *      extension  CDATA #REQUIRED
     *      mimetype  CDATA #REQUIRED
     *    >
     * <!ELEMENT defaultmimetype (CDATA) >
     * 
*

* The <mimetypeproperties/> settings have been deprecated and will * be ignored with a warning. Instead you can use the * {@link SimpleWebdavServlet#INIT_PARAM_MIME_INFO mime-info} * servlet initialization parameter to customize the media type settings. * * @param stream */ public void parse(InputStream stream) { try { Element config = DomUtil.parseDocument(stream).getDocumentElement(); if (config == null) { log.warn("Mandatory 'config' element is missing."); return; } // iomanager config entry Element el = DomUtil.getChildElement(config, ELEMENT_IOMANAGER, null); if (el != null) { Object inst = buildClassFromConfig(el); if (inst != null && inst instanceof IOManager) { ioManager = (IOManager)inst; ioManager.setDetector(detector); // get optional 'iohandler' child elements and populate the // ioManager with the instances ElementIterator iohElements = DomUtil.getChildren(el, ELEMENT_IOHANDLER, null); while (iohElements.hasNext()) { Element iohEl = iohElements.nextElement(); inst = buildClassFromConfig(iohEl); if (inst != null && inst instanceof IOHandler) { IOHandler handler = (IOHandler) inst; setParameters(handler, iohEl); ioManager.addIOHandler(handler); } else { log.warn("Not a valid IOHandler : " + getClassName(iohEl)); } } } else { log.warn("'iomanager' element does not define a valid IOManager."); } } else { log.warn("'iomanager' element is missing."); } // propertymanager config entry el = DomUtil.getChildElement(config, ELEMENT_PROPERTYMANAGER, null); if (el != null) { Object inst = buildClassFromConfig(el); if (inst != null && inst instanceof PropertyManager) { propManager = (PropertyManager)inst; // get optional 'iohandler' child elements and populate the // ioManager with the instances ElementIterator iohElements = DomUtil.getChildren(el, ELEMENT_PROPERTYHANDLER, null); while (iohElements.hasNext()) { Element iohEl = iohElements.nextElement(); inst = buildClassFromConfig(iohEl); if (inst != null && inst instanceof PropertyHandler) { PropertyHandler handler = (PropertyHandler) inst; setParameters(handler, iohEl); propManager.addPropertyHandler(handler); } else { log.warn("Not a valid PropertyHandler : " + getClassName(iohEl)); } } } else { log.warn("'propertymanager' element does not define a valid PropertyManager."); } } else { log.debug("'propertymanager' element is missing."); } // copymovemanager config entry el = DomUtil.getChildElement(config, ELEMENT_COPYMOVEMANAGER, null); if (el != null) { Object inst = buildClassFromConfig(el); if (inst != null && inst instanceof CopyMoveManager) { cmManager = (CopyMoveManager) inst; // get optional 'copymovehandler' child elements and populate // the copy move manager with the instances ElementIterator iohElements = DomUtil.getChildren(el, ELEMENT_COPYMOVEHANDLER, null); while (iohElements.hasNext()) { Element iohEl = iohElements.nextElement(); inst = buildClassFromConfig(iohEl); if (inst != null && inst instanceof CopyMoveHandler) { CopyMoveHandler handler = (CopyMoveHandler) inst; setParameters(handler, iohEl); cmManager.addCopyMoveHandler(handler); } else { log.warn("Not a valid CopyMoveHandler : " + getClassName(iohEl)); } } } else { log.warn("'copymovemanager' element does not define a valid CopyMoveManager."); } } else { log.debug("'copymovemanager' element is missing."); } // collection/non-collection config entry el = DomUtil.getChildElement(config, "collection", null); if (el != null) { nodetypeNames = parseNodeTypesEntry(el); collectionNames = true; } else if ((el = DomUtil.getChildElement(config, "noncollection", null)) != null) { nodetypeNames = parseNodeTypesEntry(el); collectionNames = false; } // todo: should check if both 'noncollection' and 'collection' are present and write a warning // filter config entry el = DomUtil.getChildElement(config, "filter", null); if (el != null) { Object inst = buildClassFromConfig(el); if (inst != null && inst instanceof ItemFilter) { itemFilter = (ItemFilter)inst; } if (itemFilter != null) { itemFilter.setFilteredNodetypes(parseNodeTypesEntry(el)); parseNamespacesEntry(el); } } else { log.debug("No 'filter' element specified."); } el = DomUtil.getChildElement(config, "mimetypeproperties", null); if (el != null) { log.warn("Ignoring deprecated mimetypeproperties settings"); } } catch (IOException e) { log.debug("Invalid resource configuration: " + e.getMessage()); } catch (ParserConfigurationException e) { log.warn("Failed to parse resource configuration: " + e.getMessage()); } catch (SAXException e) { log.warn("Failed to parse resource configuration: " + e.getMessage()); } } private void parseNamespacesEntry(Element parent) { Element namespaces = DomUtil.getChildElement(parent, "namespaces", null); if (namespaces != null) { List l = new ArrayList(); // retrieve prefix child elements ElementIterator it = DomUtil.getChildren(namespaces, "prefix", null); while (it.hasNext()) { Element e = it.nextElement(); l.add(DomUtil.getText(e)); } String[] prefixes = l.toArray(new String[l.size()]); l.clear(); // retrieve uri child elements it = DomUtil.getChildren(namespaces, "uri", null); while (it.hasNext()) { Element e = it.nextElement(); l.add(DomUtil.getText(e)); } String[] uris = l.toArray(new String[l.size()]); itemFilter.setFilteredPrefixes(prefixes); itemFilter.setFilteredURIs(uris); } } private static String[] parseNodeTypesEntry(Element parent) { String[] ntNames; Element nodetypes = DomUtil.getChildElement(parent, "nodetypes", null); if (nodetypes != null) { List l = new ArrayList(); ElementIterator it = DomUtil.getChildren(nodetypes, "nodetype", null); while (it.hasNext()) { Element e = it.nextElement(); l.add(DomUtil.getText(e)); } ntNames = l.toArray(new String[l.size()]); } else { ntNames = new String[0]; } return ntNames; } private static Object buildClassFromConfig(Element parent) { Object instance = null; Element classElem = DomUtil.getChildElement(parent, "class", null); if (classElem != null) { // contains a 'class' child node try { String className = DomUtil.getAttribute(classElem, "name", null); if (className != null) { Class c = Class.forName(className); instance = c.newInstance(); } else { log.error("Invalid configuration: missing 'class' element"); } } catch (Exception e) { log.error("Error while create class instance: " + e.getMessage()); } } return instance; } private static String getClassName(Element parent) { String className = null; Element classElem = DomUtil.getChildElement(parent, "class", null); if (classElem != null) { className = DomUtil.getAttribute(classElem, "name", null); } return (className == null) ? "" : className; } /** * Retrieve 'param' elements for the specified xmlElement and * use the public setter methods of the given instance to set * the corresponding instance fields. * * @param instance * @param xmlElement */ private static void setParameters(Object instance, Element xmlElement) { ElementIterator paramElems = DomUtil.getChildren(xmlElement, ELEMENT_PARAM, Namespace.EMPTY_NAMESPACE); if (paramElems.hasNext()) { Map setters = getSetters(instance.getClass()); if (!setters.isEmpty()) { while (paramElems.hasNext()) { Element parameter = paramElems.next(); String name = DomUtil.getAttribute(parameter, ATTR_NAME, null); String value = DomUtil.getAttribute(parameter, ATTR_VALUE, null); if (name == null || value == null) { log.error("Parameter name or value missing -> ignore."); continue; } Method setter = setters.get(name); if (setter != null) { Class type = setter.getParameterTypes()[0]; try { if (type.isAssignableFrom(String.class) || type.isAssignableFrom(Object.class)) { setter.invoke(instance, value); } else if (type.isAssignableFrom(Boolean.TYPE) || type.isAssignableFrom(Boolean.class)) { setter.invoke(instance, Boolean.valueOf(value)); } else if (type.isAssignableFrom(Integer.TYPE) || type.isAssignableFrom(Integer.class)) { setter.invoke(instance, Integer.valueOf(value)); } else if (type.isAssignableFrom(Long.TYPE) || type.isAssignableFrom(Long.class)) { setter.invoke(instance, Long.valueOf(value)); } else if (type.isAssignableFrom(Double.TYPE) || type.isAssignableFrom(Double.class)) { setter.invoke(instance, Double.valueOf(value)); } else { log.error("Cannot set configuration property " + name); } } catch (Exception e) { log.error("Invalid format (" + value + ") for property " + name + " of class " + instance.getClass().getName(), e); } } } } } } private static Map getSetters(Class cl) { Map methods = new HashMap(); for (Method method : cl.getMethods()) { String name = method.getName(); if (name.startsWith("set") && name.length() > 3 && Modifier.isPublic(method.getModifiers()) && !Modifier.isStatic(method.getModifiers()) && Void.TYPE.equals(method.getReturnType()) && method.getParameterTypes().length == 1) { methods.put(name.substring(3, 4).toLowerCase() + name.substring(4), method); } } return methods; } /** * * @return */ public IOManager getIOManager() { if (ioManager == null) { log.debug("Missing io-manager > building DefaultIOManager "); ioManager = new DefaultIOManager(); ioManager.setDetector(detector); } return ioManager; } /** * * @return */ public PropertyManager getPropertyManager() { if (propManager == null) { log.debug("Missing property-manager > building default."); propManager = PropertyManagerImpl.getDefaultManager(); } return propManager; } /** * * @return */ public CopyMoveManager getCopyMoveManager() { if (cmManager == null) { log.debug("Missing copymove-manager > building default."); cmManager = CopyMoveManagerImpl.getDefaultManager(); } return cmManager; } /** * Returns true, if the given item represents a {@link Node node} that is * either any of the nodetypes specified to represent a collection or * none of the nodetypes specified to represent a non-collection, respectively. * If no valid configuration entry is present, this method returns true * for node items. For items which are not a node, this method always * returns false. * * @param item * @return true if the given item is a node that represents a webdav * collection, false otherwise. */ public boolean isCollectionResource(Item item) { if (item.isNode()) { boolean isCollection = true; Node n = (Node)item; try { for (int i = 0; i < nodetypeNames.length && isCollection; i++) { isCollection = collectionNames ? n.isNodeType(nodetypeNames[i]) : !n.isNodeType(nodetypeNames[i]); } } catch (RepositoryException e) { log.warn(e.getMessage()); } return isCollection; } else { return false; } } /** * Returns the item filter specified with the configuration or {@link DefaultItemFilter} * if the configuration was missing the corresponding entry or the parser failed * to build a ItemFilter instance from the configuration. * * @return item filter as defined by the config or {@link DefaultItemFilter} */ public ItemFilter getItemFilter() { if (itemFilter == null) { log.debug("Missing resource filter > building DefaultItemFilter "); itemFilter = new DefaultItemFilter(); } return itemFilter; } /** * Returns the configured content type detector. * * @return content type detector */ public Detector getDetector() { return detector; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy