This project has retired. For details please refer to its Attic page.
CmisServiceWrapperManager xref
View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.chemistry.opencmis.server.support.wrapper;
20  
21  import java.lang.reflect.Constructor;
22  import java.util.Arrays;
23  import java.util.Locale;
24  import java.util.Map;
25  import java.util.TreeMap;
26  
27  import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
28  import org.apache.chemistry.opencmis.commons.impl.ClassLoaderUtil;
29  import org.apache.chemistry.opencmis.commons.server.CmisService;
30  import org.slf4j.Logger;
31  import org.slf4j.LoggerFactory;
32  
33  /**
34   * Manages a list of CMIS service wrappers.
35   */
36  public class CmisServiceWrapperManager {
37  
38      private static final Logger LOG = LoggerFactory.getLogger(CmisServiceWrapperManager.class);
39  
40      private static final String PARAMS_SERVICE_WRAPPER_PREFIX = "servicewrapper.";
41  
42      private WrapperDefinition outerMost;
43      private WrapperDefinition innerMost;
44  
45      /**
46       * Constructor.
47       */
48      public CmisServiceWrapperManager() {
49          outerMost = null;
50          innerMost = null;
51      }
52  
53      /**
54       * Adds an outer-most (called first) wrapper.
55       * 
56       * @param wrapperClass
57       *            the wrapper class
58       * @param params
59       *            wrapper parameters
60       */
61      public void addOuterWrapper(Class<? extends AbstractCmisServiceWrapper> wrapperClass, Object... params) {
62          WrapperDefinition wd = new WrapperDefinition(wrapperClass, params);
63          if (outerMost == null) {
64              outerMost = wd;
65              innerMost = wd;
66          } else {
67              outerMost.setOuterWrapper(wd);
68              outerMost = wd;
69          }
70  
71          LOG.debug("Added outer service wrapper: {}", wrapperClass.getName());
72      }
73  
74      /**
75       * Adds an inner-most (called last) wrapper.
76       * 
77       * @param wrapperClass
78       *            the wrapper class
79       * @param params
80       *            wrapper parameters
81       */
82      public void addInnerWrapper(Class<? extends AbstractCmisServiceWrapper> wrapperClass, Object... params) {
83          WrapperDefinition wd = new WrapperDefinition(wrapperClass, params);
84          if (innerMost == null) {
85              outerMost = wd;
86              innerMost = wd;
87          } else {
88              innerMost.setInnerWrapper(wd);
89              innerMost = wd;
90          }
91  
92          LOG.debug("Added inner service wrapper: {}", wrapperClass.getName());
93      }
94  
95      /**
96       * Gets wrapper settings from the service factory parameters and adds them
97       * to the wrappers.
98       * <p>
99       * The factory parameters properties file should look like this:
100      * 
101      * <pre>
102      * servicewrapper.1=com.example.my.SimpleWrapper
103      * servicewrapper.2=com.example.my.AdvancedWrapper,1,cmis:documents
104      * servicewrapper.3=com.example.my.DebuggingWrapper,testRepositoryId
105      * </pre>
106      * 
107      * Syntax:
108      * {@code servicewrapper.&lt;position>=&lt;classname>[,parameter1[,parameter2[...]]]}
109      * 
110      * @param parameters
111      *            service factory parameters
112      */
113     @SuppressWarnings("unchecked")
114     public void addWrappersFromServiceFactoryParameters(Map<String, String> parameters) {
115         if (parameters == null) {
116             return;
117         }
118 
119         TreeMap<Integer, WrapperDefinition> wrappers = new TreeMap<Integer, WrapperDefinition>();
120 
121         for (Map.Entry<String, String> entry : parameters.entrySet()) {
122             String key = entry.getKey().trim().toLowerCase(Locale.ENGLISH);
123             if (key.startsWith(PARAMS_SERVICE_WRAPPER_PREFIX) && entry.getKey() != null) {
124                 int index = 0;
125                 try {
126                     index = Integer.valueOf(key.substring(PARAMS_SERVICE_WRAPPER_PREFIX.length()));
127                 } catch (NumberFormatException e) {
128                     throw new CmisRuntimeException("Invalid service wrapper configuration: " + key, e);
129                 }
130 
131                 String[] value = entry.getValue().trim().split(",");
132                 if (value.length > 0) {
133                     Class<?> wrapperClass = null;
134                     try {
135                         wrapperClass = ClassLoaderUtil.loadClass(value[0]);
136                     } catch (ClassNotFoundException e) {
137                         throw new CmisRuntimeException("Service wrapper class not found: " + value[0], e);
138                     }
139 
140                     if (!AbstractCmisServiceWrapper.class.isAssignableFrom(wrapperClass)) {
141                         throw new CmisRuntimeException("Class is not a service wrapper: " + value[0]);
142                     }
143 
144                     Object[] params = null;
145                     if (value.length > 1) {
146                         params = new Object[value.length - 1];
147                         System.arraycopy(value, 1, params, 0, params.length);
148                     }
149 
150                     if (wrappers.containsKey(index)) {
151                         throw new CmisRuntimeException("More than one service wrapper at the same position: " + index);
152                     }
153 
154                     if (LOG.isTraceEnabled()) {
155                         LOG.trace("Found wrapper at index {}: {}{}", index, wrapperClass.getName(), params == null ? ""
156                                 : Arrays.asList(params).toString());
157                     }
158 
159                     wrappers.put(index, new WrapperDefinition(
160                             (Class<? extends AbstractCmisServiceWrapper>) wrapperClass, params));
161                 }
162             }
163         }
164 
165         if (!wrappers.isEmpty()) {
166             WrapperDefinition first = null;
167             WrapperDefinition prev = null;
168             for (WrapperDefinition def : wrappers.values()) {
169                 def.setOuterWrapper(prev);
170                 prev = def;
171                 if (first == null) {
172                     first = def;
173                 }
174 
175                 LOG.debug("Added service wrapper: {}", def.getWrapperClass().getName());
176             }
177 
178             if (outerMost == null) {
179                 outerMost = first;
180                 innerMost = prev;
181             } else {
182                 outerMost.setOuterWrapper(prev);
183                 outerMost = first;
184             }
185         }
186     }
187 
188     /**
189      * Removes the outer-most wrapper.
190      */
191     public void removeOuterWrapper() {
192         if (outerMost != null) {
193             outerMost = outerMost.getInnerWrapper();
194             if (outerMost == null) {
195                 innerMost = null;
196             } else {
197                 outerMost.setOuterWrapper(null);
198             }
199         }
200     }
201 
202     /**
203      * Removes the inner-most wrapper.
204      */
205     public void removeInnerWrapper() {
206         if (innerMost != null) {
207             innerMost = innerMost.getOuterWrapper();
208             if (innerMost == null) {
209                 outerMost = null;
210             } else {
211                 innerMost.setInnerWrapper(null);
212             }
213         }
214     }
215 
216     /**
217      * Wraps a service with all configured wrappers.
218      * 
219      * @param service
220      *            the CMIS service object
221      * @return the wrapped service
222      */
223     public CmisService wrap(CmisService service) {
224         CmisService result = service;
225 
226         WrapperDefinition def = innerMost;
227         while (def != null) {
228             result = def.createWrapperObject(result);
229             def = def.getOuterWrapper();
230         }
231 
232         return result;
233     }
234 
235     @Override
236     public String toString() {
237         StringBuilder sb = new StringBuilder(128);
238 
239         WrapperDefinition def = outerMost;
240         while (def != null) {
241 
242             sb.append('[');
243             sb.append(def.toString());
244             sb.append(']');
245 
246             def = def.getInnerWrapper();
247         }
248 
249         return sb.toString();
250     }
251 
252     /**
253      * Wrapper Definition.
254      */
255     private static class WrapperDefinition {
256 
257         private static final Class<?>[] CONSTRUCTOR_PARAMETERS = new Class<?>[] { CmisService.class };
258 
259         private final Class<? extends AbstractCmisServiceWrapper> wrapperClass;
260         private final Constructor<? extends AbstractCmisServiceWrapper> wrapperConstructor;
261         private final Object[] params;
262 
263         private WrapperDefinition outer;
264         private WrapperDefinition inner;
265 
266         public WrapperDefinition(Class<? extends AbstractCmisServiceWrapper> wrapperClass, Object... params) {
267             this.wrapperClass = wrapperClass;
268             this.params = params;
269 
270             if (wrapperClass == null) {
271                 throw new CmisRuntimeException("Wrapper class must be set!");
272             }
273 
274             try {
275                 wrapperConstructor = wrapperClass.getConstructor(CONSTRUCTOR_PARAMETERS);
276             } catch (Exception e) {
277                 throw new CmisRuntimeException("Could not access constructor of service wrapper "
278                         + wrapperClass.getName() + ": " + e.toString(), e);
279             }
280         }
281 
282         public Class<? extends AbstractCmisServiceWrapper> getWrapperClass() {
283             return wrapperClass;
284         }
285 
286         public AbstractCmisServiceWrapper createWrapperObject(CmisService service) {
287             try {
288                 AbstractCmisServiceWrapper wrapper = wrapperConstructor.newInstance(service);
289                 wrapper.initialize(params);
290 
291                 return wrapper;
292             } catch (Exception e) {
293                 throw new CmisRuntimeException("Could not instantiate service wrapper " + wrapperClass.getName() + ": "
294                         + e.toString(), e);
295             }
296         }
297 
298         public void setOuterWrapper(WrapperDefinition wrapper) {
299             outer = wrapper;
300             if (wrapper != null) {
301                 wrapper.inner = this;
302             }
303         }
304 
305         public WrapperDefinition getOuterWrapper() {
306             return outer;
307         }
308 
309         public void setInnerWrapper(WrapperDefinition wrapper) {
310             inner = wrapper;
311             if (wrapper != null) {
312                 wrapper.outer = this;
313             }
314         }
315 
316         public WrapperDefinition getInnerWrapper() {
317             return inner;
318         }
319 
320         @Override
321         public String toString() {
322             StringBuilder sb = new StringBuilder(128);
323 
324             sb.append(wrapperClass.getName());
325 
326             if (params != null) {
327                 for (int i = 0; i < params.length; i++) {
328                     sb.append(',');
329                     sb.append(params[i]);
330                 }
331             }
332 
333             return sb.toString();
334         }
335     }
336 }