blob: da3fd5af87c3549c49cdc68e9b7c6f7d4bd141e3 [file] [log] [blame]
/*
* 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.chemistry.opencmis.server.support.wrapper;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
import org.apache.chemistry.opencmis.commons.impl.ClassLoaderUtil;
import org.apache.chemistry.opencmis.commons.server.CmisService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Manages a list of CMIS service wrappers.
*/
public class CmisServiceWrapperManager {
private static final Logger LOG = LoggerFactory.getLogger(CmisServiceWrapperManager.class);
private static final String PARAMS_SERVICE_WRAPPER_PREFIX = "servicewrapper.";
private WrapperDefinition outerMost;
private WrapperDefinition innerMost;
/**
* Constructor.
*/
public CmisServiceWrapperManager() {
outerMost = null;
innerMost = null;
}
/**
* Adds an outer-most (called first) wrapper.
*
* @param wrapperClass
* the wrapper class
* @param params
* wrapper parameters
*/
public void addOuterWrapper(Class<? extends AbstractCmisServiceWrapper> wrapperClass, Object... params) {
WrapperDefinition wd = new WrapperDefinition(wrapperClass, params);
if (outerMost == null) {
outerMost = wd;
innerMost = wd;
} else {
outerMost.setOuterWrapper(wd);
outerMost = wd;
}
LOG.debug("Added outer service wrapper: {}", wrapperClass.getName());
}
/**
* Adds an inner-most (called last) wrapper.
*
* @param wrapperClass
* the wrapper class
* @param params
* wrapper parameters
*/
public void addInnerWrapper(Class<? extends AbstractCmisServiceWrapper> wrapperClass, Object... params) {
WrapperDefinition wd = new WrapperDefinition(wrapperClass, params);
if (innerMost == null) {
outerMost = wd;
innerMost = wd;
} else {
innerMost.setInnerWrapper(wd);
innerMost = wd;
}
LOG.debug("Added inner service wrapper: {}", wrapperClass.getName());
}
/**
* Gets wrapper settings from the service factory parameters and adds them
* to the wrappers.
* <p>
* The factory parameters properties file should look like this:
*
* <pre>
* servicewrapper.1=com.example.my.SimpleWrapper
* servicewrapper.2=com.example.my.AdvancedWrapper,1,cmis:documents
* servicewrapper.3=com.example.my.DebuggingWrapper,testRepositoryId
* </pre>
*
* Syntax:
* {@code servicewrapper.&lt;position>=&lt;classname>[,parameter1[,parameter2[...]]]}
*
* @param parameters
* service factory parameters
*/
@SuppressWarnings("unchecked")
public void addWrappersFromServiceFactoryParameters(Map<String, String> parameters) {
if (parameters == null) {
return;
}
TreeMap<Integer, WrapperDefinition> wrappers = new TreeMap<Integer, WrapperDefinition>();
for (Map.Entry<String, String> entry : parameters.entrySet()) {
String key = entry.getKey().trim().toLowerCase(Locale.ENGLISH);
if (key.startsWith(PARAMS_SERVICE_WRAPPER_PREFIX) && entry.getKey() != null) {
int index = 0;
try {
index = Integer.valueOf(key.substring(PARAMS_SERVICE_WRAPPER_PREFIX.length()));
} catch (NumberFormatException e) {
throw new CmisRuntimeException("Invalid service wrapper configuration: " + key, e);
}
String[] value = entry.getValue().trim().split(",");
if (value.length > 0) {
Class<?> wrapperClass = null;
try {
wrapperClass = ClassLoaderUtil.loadClass(value[0]);
} catch (ClassNotFoundException e) {
throw new CmisRuntimeException("Service wrapper class not found: " + value[0], e);
}
if (!AbstractCmisServiceWrapper.class.isAssignableFrom(wrapperClass)) {
throw new CmisRuntimeException("Class is not a service wrapper: " + value[0]);
}
Object[] params = null;
if (value.length > 1) {
params = new Object[value.length - 1];
System.arraycopy(value, 1, params, 0, params.length);
}
if (wrappers.containsKey(index)) {
throw new CmisRuntimeException("More than one service wrapper at the same position: " + index);
}
if (LOG.isTraceEnabled()) {
LOG.trace("Found wrapper at index {}: {}{}", index, wrapperClass.getName(), params == null ? ""
: Arrays.asList(params).toString());
}
wrappers.put(index, new WrapperDefinition(
(Class<? extends AbstractCmisServiceWrapper>) wrapperClass, params));
}
}
}
if (!wrappers.isEmpty()) {
WrapperDefinition first = null;
WrapperDefinition prev = null;
for (WrapperDefinition def : wrappers.values()) {
def.setOuterWrapper(prev);
prev = def;
if (first == null) {
first = def;
}
LOG.debug("Added service wrapper: {}", def.getWrapperClass().getName());
}
if (outerMost == null) {
outerMost = first;
innerMost = prev;
} else {
outerMost.setOuterWrapper(prev);
outerMost = first;
}
}
}
/**
* Removes the outer-most wrapper.
*/
public void removeOuterWrapper() {
if (outerMost != null) {
outerMost = outerMost.getInnerWrapper();
if (outerMost == null) {
innerMost = null;
} else {
outerMost.setOuterWrapper(null);
}
}
}
/**
* Removes the inner-most wrapper.
*/
public void removeInnerWrapper() {
if (innerMost != null) {
innerMost = innerMost.getOuterWrapper();
if (innerMost == null) {
outerMost = null;
} else {
innerMost.setInnerWrapper(null);
}
}
}
/**
* Wraps a service with all configured wrappers.
*
* @param service
* the CMIS service object
* @return the wrapped service
*/
public CmisService wrap(CmisService service) {
CmisService result = service;
WrapperDefinition def = innerMost;
while (def != null) {
result = def.createWrapperObject(result);
def = def.getOuterWrapper();
}
return result;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
WrapperDefinition def = outerMost;
while (def != null) {
sb.append('[');
sb.append(def.toString());
sb.append(']');
def = def.getInnerWrapper();
}
return sb.toString();
}
/**
* Wrapper Definition.
*/
private static class WrapperDefinition {
private static final Class<?>[] CONSTRUCTOR_PARAMETERS = new Class<?>[] { CmisService.class };
private final Class<? extends AbstractCmisServiceWrapper> wrapperClass;
private final Constructor<? extends AbstractCmisServiceWrapper> wrapperConstructor;
private final Object[] params;
private WrapperDefinition outer;
private WrapperDefinition inner;
public WrapperDefinition(Class<? extends AbstractCmisServiceWrapper> wrapperClass, Object... params) {
this.wrapperClass = wrapperClass;
this.params = params;
if (wrapperClass == null) {
throw new CmisRuntimeException("Wrapper class must be set!");
}
try {
wrapperConstructor = wrapperClass.getConstructor(CONSTRUCTOR_PARAMETERS);
} catch (Exception e) {
throw new CmisRuntimeException("Could not access constructor of service wrapper "
+ wrapperClass.getName() + ": " + e.toString(), e);
}
}
public Class<? extends AbstractCmisServiceWrapper> getWrapperClass() {
return wrapperClass;
}
public AbstractCmisServiceWrapper createWrapperObject(CmisService service) {
try {
AbstractCmisServiceWrapper wrapper = wrapperConstructor.newInstance(service);
wrapper.initialize(params);
return wrapper;
} catch (Exception e) {
throw new CmisRuntimeException("Could not instantiate service wrapper " + wrapperClass.getName() + ": "
+ e.toString(), e);
}
}
public void setOuterWrapper(WrapperDefinition wrapper) {
outer = wrapper;
if (wrapper != null) {
wrapper.inner = this;
}
}
public WrapperDefinition getOuterWrapper() {
return outer;
}
public void setInnerWrapper(WrapperDefinition wrapper) {
inner = wrapper;
if (wrapper != null) {
wrapper.outer = this;
}
}
public WrapperDefinition getInnerWrapper() {
return inner;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(wrapperClass.getName());
if (params != null) {
for (int i = 0; i < params.length; i++) {
sb.append(',');
sb.append(params[i]);
}
}
return sb.toString();
}
}
}