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.client.bindings.spi.atompub;
20  
21  import java.io.Serializable;
22  import java.util.HashSet;
23  import java.util.Map;
24  import java.util.Set;
25  
26  import org.apache.chemistry.opencmis.client.bindings.cache.Cache;
27  import org.apache.chemistry.opencmis.client.bindings.cache.impl.CacheImpl;
28  import org.apache.chemistry.opencmis.client.bindings.cache.impl.ContentTypeCacheLevelImpl;
29  import org.apache.chemistry.opencmis.client.bindings.cache.impl.LruCacheLevelImpl;
30  import org.apache.chemistry.opencmis.client.bindings.cache.impl.MapCacheLevelImpl;
31  import org.apache.chemistry.opencmis.client.bindings.spi.BindingSession;
32  import org.apache.chemistry.opencmis.commons.SessionParameter;
33  import org.apache.chemistry.opencmis.commons.SessionParameterDefaults;
34  import org.apache.chemistry.opencmis.commons.impl.Constants;
35  import org.apache.chemistry.opencmis.commons.impl.IOUtils;
36  import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
37  
38  /**
39   * Link cache.
40   */
41  public class LinkCache implements Serializable {
42  
43      private static final long serialVersionUID = 1L;
44  
45      private static final Set<String> KNOWN_LINKS = new HashSet<String>();
46  
47      static {
48          KNOWN_LINKS.add(Constants.REL_ACL);
49          KNOWN_LINKS.add(Constants.REL_DOWN);
50          KNOWN_LINKS.add(Constants.REL_UP);
51          KNOWN_LINKS.add(Constants.REL_FOLDERTREE);
52          KNOWN_LINKS.add(Constants.REL_RELATIONSHIPS);
53          KNOWN_LINKS.add(Constants.REL_SELF);
54          KNOWN_LINKS.add(Constants.REL_ALLOWABLEACTIONS);
55          KNOWN_LINKS.add(Constants.REL_EDITMEDIA);
56          KNOWN_LINKS.add(Constants.REL_POLICIES);
57          KNOWN_LINKS.add(Constants.REL_VERSIONHISTORY);
58          KNOWN_LINKS.add(Constants.REL_WORKINGCOPY);
59          KNOWN_LINKS.add(AtomPubParser.LINK_REL_CONTENT);
60      }
61  
62      private final Cache linkCache;
63      private final Cache typeLinkCache;
64      private final Cache collectionLinkCache;
65      private final Cache templateCache;
66      private final Cache repositoryLinkCache;
67  
68      /**
69       * Constructor.
70       */
71      public LinkCache(BindingSession session) {
72          int repCount = session.get(SessionParameter.CACHE_SIZE_REPOSITORIES,
73                  SessionParameterDefaults.CACHE_SIZE_REPOSITORIES);
74          if (repCount < 1) {
75              repCount = SessionParameterDefaults.CACHE_SIZE_REPOSITORIES;
76          }
77  
78          int typeCount = session.get(SessionParameter.CACHE_SIZE_TYPES, SessionParameterDefaults.CACHE_SIZE_TYPES);
79          if (typeCount < 1) {
80              typeCount = SessionParameterDefaults.CACHE_SIZE_TYPES;
81          }
82  
83          int objCount = session.get(SessionParameter.CACHE_SIZE_LINKS, SessionParameterDefaults.CACHE_SIZE_LINKS);
84          if (objCount < 1) {
85              objCount = SessionParameterDefaults.CACHE_SIZE_LINKS;
86          }
87  
88          linkCache = new CacheImpl("Link Cache");
89          linkCache.initialize(new String[] {
90                  MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=" + repCount, // repository
91                  LruCacheLevelImpl.class.getName() + " " + LruCacheLevelImpl.MAX_ENTRIES + "=" + objCount, // id
92                  MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=12", // rel
93                  ContentTypeCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=3,"
94                          + MapCacheLevelImpl.SINGLE_VALUE + "=true" // type
95          });
96  
97          typeLinkCache = new CacheImpl("Type Link Cache");
98          typeLinkCache.initialize(new String[] {
99                  MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=" + repCount, // repository
100                 LruCacheLevelImpl.class.getName() + " " + LruCacheLevelImpl.MAX_ENTRIES + "=" + typeCount, // id
101                 MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=12", // rel
102                 ContentTypeCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=3,"
103                         + MapCacheLevelImpl.SINGLE_VALUE + "=true"// type
104         });
105 
106         collectionLinkCache = new CacheImpl("Collection Link Cache");
107         collectionLinkCache.initialize(new String[] {
108                 MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=" + repCount, // repository
109                 MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=8" // collection
110         });
111 
112         templateCache = new CacheImpl("URI Template Cache");
113         templateCache.initialize(new String[] {
114                 MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=" + repCount, // repository
115                 MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=6" // type
116         });
117 
118         repositoryLinkCache = new CacheImpl("Repository Link Cache");
119         repositoryLinkCache.initialize(new String[] {
120                 MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=" + repCount, // repository
121                 MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=6" // rel
122         });
123     }
124 
125     /**
126      * Adds a link.
127      */
128     public void addLink(String repositoryId, String id, String rel, String type, String link) {
129         if (KNOWN_LINKS.contains(rel)) {
130             linkCache.put(link, repositoryId, id, rel, type);
131         } else if (Constants.REL_ALTERNATE.equals(rel)) {
132             // use streamId instead of type as discriminating parameter
133             String streamId = extractStreamId(link);
134             if (streamId != null) {
135                 linkCache.put(link, repositoryId, id, rel, streamId);
136             }
137         }
138     }
139 
140     /**
141      * Tries to extract a streamId from an alternate link.
142      */
143     // this is not strictly in the spec
144     protected String extractStreamId(String link) {
145         int i = link.lastIndexOf('?');
146         if (i > 0) {
147             String[] params = link.substring(i + 1).split("&");
148             for (String param : params) {
149                 String[] parts = param.split("=", 2);
150                 if (parts[0].equals(Constants.PARAM_STREAM_ID) && parts.length == 2) {
151                     return parts[1];
152                 }
153             }
154         }
155         return null;
156     }
157 
158     /**
159      * Removes all links of an object.
160      */
161     public void removeLinks(String repositoryId, String id) {
162         linkCache.remove(repositoryId, id);
163     }
164 
165     /**
166      * Gets a link.
167      */
168     public String getLink(String repositoryId, String id, String rel, String type) {
169         return (String) linkCache.get(repositoryId, id, rel, type);
170     }
171 
172     /**
173      * Gets a link.
174      */
175     public String getLink(String repositoryId, String id, String rel) {
176         return getLink(repositoryId, id, rel, null);
177     }
178 
179     /**
180      * Checks a link.
181      */
182     public int checkLink(String repositoryId, String id, String rel, String type) {
183         return linkCache.check(repositoryId, id, rel, type);
184     }
185 
186     /**
187      * Locks the link cache.
188      */
189     public void lockLinks() {
190         linkCache.writeLock();
191     }
192 
193     /**
194      * Unlocks the link cache.
195      */
196     public void unlockLinks() {
197         linkCache.writeUnlock();
198     }
199 
200     /**
201      * Adds a type link.
202      */
203     public void addTypeLink(String repositoryId, String id, String rel, String type, String link) {
204         if (KNOWN_LINKS.contains(rel)) {
205             typeLinkCache.put(link, repositoryId, id, rel, type);
206         }
207     }
208 
209     /**
210      * Removes all links of a type.
211      */
212     public void removeTypeLinks(String repositoryId, String id) {
213         typeLinkCache.remove(repositoryId, id);
214     }
215 
216     /**
217      * Gets a type link.
218      */
219     public String getTypeLink(String repositoryId, String id, String rel, String type) {
220         return (String) typeLinkCache.get(repositoryId, id, rel, type);
221     }
222 
223     /**
224      * Locks the type link cache.
225      */
226     public void lockTypeLinks() {
227         typeLinkCache.writeLock();
228     }
229 
230     /**
231      * Unlocks the type link cache.
232      */
233     public void unlockTypeLinks() {
234         typeLinkCache.writeUnlock();
235     }
236 
237     /**
238      * Adds a collection.
239      */
240     public void addCollection(String repositoryId, String collection, String link) {
241         collectionLinkCache.put(link, repositoryId, collection);
242     }
243 
244     /**
245      * Gets a collection.
246      */
247     public String getCollection(String repositoryId, String collection) {
248         return (String) collectionLinkCache.get(repositoryId, collection);
249     }
250 
251     /**
252      * Adds an URI template.
253      */
254     public void addTemplate(String repositoryId, String type, String link) {
255         templateCache.put(link, repositoryId, type);
256     }
257 
258     /**
259      * Gets an URI template and replaces place holders with the given
260      * parameters.
261      */
262     public String getTemplateLink(String repositoryId, String type, Map<String, Object> parameters) {
263         String template = (String) templateCache.get(repositoryId, type);
264         if (template == null) {
265             return null;
266         }
267 
268         StringBuilder result = new StringBuilder(128);
269         StringBuilder param = new StringBuilder(32);
270 
271         boolean paramMode = false;
272         for (int i = 0; i < template.length(); i++) {
273             char c = template.charAt(i);
274 
275             if (paramMode) {
276                 if (c == '}') {
277                     paramMode = false;
278 
279                     String paramValue = UrlBuilder.normalizeParameter(parameters.get(param.toString()));
280                     if (paramValue != null) {
281                         result.append(IOUtils.encodeURL(paramValue));
282                     }
283 
284                     param.setLength(0);
285                 } else {
286                     param.append(c);
287                 }
288             } else {
289                 if (c == '{') {
290                     paramMode = true;
291                 } else {
292                     result.append(c);
293                 }
294             }
295         }
296 
297         return result.toString();
298     }
299 
300     /**
301      * Adds a collection.
302      */
303     public void addRepositoryLink(String repositoryId, String rel, String link) {
304         repositoryLinkCache.put(link, repositoryId, rel);
305     }
306 
307     /**
308      * Gets a collection.
309      */
310     public String getRepositoryLink(String repositoryId, String rel) {
311         return (String) repositoryLinkCache.get(repositoryId, rel);
312     }
313 
314     /**
315      * Removes all entries of the given repository from the caches.
316      */
317     public void clearRepository(String repositoryId) {
318         linkCache.remove(repositoryId);
319         typeLinkCache.remove(repositoryId);
320         collectionLinkCache.remove(repositoryId);
321         templateCache.remove(repositoryId);
322         repositoryLinkCache.remove(repositoryId);
323     }
324 
325     /*
326      * (non-Javadoc)
327      * 
328      * @see java.lang.Object#toString()
329      */
330     @Override
331     public String toString() {
332         return "Link Cache [link cache=" + linkCache + ", type link cache=" + typeLinkCache
333                 + ", collection link cache=" + collectionLinkCache + ", repository link cache=" + repositoryLinkCache
334                 + ",  template cache=" + templateCache + "]";
335     }
336 }