001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (C) Alkacon Software (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.cmis;
029
030import org.opencms.main.CmsLog;
031import org.opencms.util.CmsStringUtil;
032
033import java.lang.reflect.InvocationHandler;
034import java.lang.reflect.InvocationTargetException;
035import java.lang.reflect.Method;
036import java.lang.reflect.Proxy;
037import java.math.BigInteger;
038import java.util.ArrayList;
039import java.util.HashSet;
040import java.util.List;
041import java.util.Map;
042import java.util.Set;
043
044import org.apache.chemistry.opencmis.commons.impl.server.AbstractServiceFactory;
045import org.apache.chemistry.opencmis.commons.server.CallContext;
046import org.apache.chemistry.opencmis.commons.server.CmisService;
047import org.apache.chemistry.opencmis.server.support.wrapper.ConformanceCmisServiceWrapper;
048import org.apache.commons.logging.Log;
049
050/**
051 * The factory class for creating the OpenCms CMIS service instances.<p>
052 */
053public class CmsCmisServiceFactory extends AbstractServiceFactory {
054
055    /**
056     * An invocation handler which wraps a service and is used for debugging/logging CMIS service calls.<p>
057     */
058    static class LoggingServiceProxy implements InvocationHandler {
059
060        /** The CMIS service interfaces. */
061        private static Set<Class<?>> m_serviceInterfaces = new HashSet<Class<?>>();
062
063        /** The wrapped service. */
064        private CmisService m_service;
065
066        /**
067         * Creates a instance.<p>
068         *
069         * @param service the service to wrap
070         */
071        public LoggingServiceProxy(CmisService service) {
072
073            m_service = service;
074        }
075
076        static {
077            for (Class<?> svcInterface : CmisService.class.getInterfaces()) {
078                m_serviceInterfaces.add(svcInterface);
079            }
080        }
081
082        /**
083         * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
084         */
085        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
086
087            try {
088                // CmisService defines some methods in addition to its base interfaces which don't correspond to CMIS service calls
089
090                boolean isServiceCall = m_serviceInterfaces.contains(method.getDeclaringClass());
091                if (isServiceCall) {
092                    LOG.info("CMIS service call: " + getCallString(method, args));
093                }
094                Object result = method.invoke(m_service, args);
095                if (isServiceCall && LOG.isDebugEnabled()) {
096                    // This can generate a *VERY LARGE AMOUNT* of data in the log file, don't activate the debug channel
097                    // unless you really need to
098                    LOG.debug("Returned '" + result + "'");
099                }
100                return result;
101            } catch (InvocationTargetException e) {
102                Throwable cause = e.getCause();
103                LOG.info(cause.getLocalizedMessage(), cause);
104                throw cause;
105            }
106        }
107
108        /**
109         * Creates a string representation of a given method call, which is used for logging.<p>
110         *
111         * @param method the method
112         * @param args the method call arguments
113         *
114         * @return a string representation of the method call
115         */
116        private String getCallString(Method method, Object[] args) {
117
118            List<String> tokens = new ArrayList<String>();
119            tokens.add(method.getName());
120            if ((args != null) && (args.length > 0)) {
121                tokens.add("=>");
122                for (Object arg : args) {
123                    tokens.add("'" + arg + "'");
124                }
125            }
126            return CmsStringUtil.listAsString(tokens, " ");
127        }
128    }
129
130    /** The logger for this class. */
131    protected static final Log LOG = CmsLog.getLog(CmsCmisServiceFactory.class);
132
133    /** Default value for maximum depth of objects to return. */
134    private static final BigInteger DEFAULT_DEPTH_OBJECTS = BigInteger.valueOf(100);
135
136    /** Default value for maximum depth of types to return. */
137    private static final BigInteger DEFAULT_DEPTH_TYPES = BigInteger.valueOf(-1);
138
139    /** Default value for maximum number of objects to return. */
140    private static final BigInteger DEFAULT_MAX_ITEMS_OBJECTS = BigInteger.valueOf(200);
141
142    /** Default value for maximum number of types to return. */
143    private static final BigInteger DEFAULT_MAX_ITEMS_TYPES = BigInteger.valueOf(50);
144
145    /**
146     * @see org.apache.chemistry.opencmis.commons.impl.server.AbstractServiceFactory#destroy()
147     */
148    @Override
149    public void destroy() {
150
151        // do nothing for now
152    }
153
154    /**
155     * @see org.apache.chemistry.opencmis.commons.impl.server.AbstractServiceFactory#getService(org.apache.chemistry.opencmis.commons.server.CallContext)
156     */
157    @Override
158    public CmisService getService(CallContext context) {
159
160        CmsCmisService service = new CmsCmisService(context);
161        CmisService proxyService = (CmisService)Proxy.newProxyInstance(
162            this.getClass().getClassLoader(),
163            new Class[] {CmisService.class},
164            new LoggingServiceProxy(service));
165        ConformanceCmisServiceWrapper wrapperService = new ConformanceCmisServiceWrapper(
166            proxyService,
167            DEFAULT_MAX_ITEMS_TYPES,
168            DEFAULT_DEPTH_TYPES,
169            DEFAULT_MAX_ITEMS_OBJECTS,
170            DEFAULT_DEPTH_OBJECTS);
171        return wrapperService;
172    }
173
174    /**
175     * @see org.apache.chemistry.opencmis.commons.impl.server.AbstractServiceFactory#init(java.util.Map)
176     */
177    @Override
178    public void init(Map<String, String> parameters) {
179
180        // do nothing for now
181    }
182}