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.OutputStream;
22  import java.math.BigInteger;
23  import java.util.ArrayList;
24  
25  import javax.xml.stream.XMLStreamWriter;
26  
27  import org.apache.chemistry.opencmis.client.bindings.spi.BindingSession;
28  import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomElement;
29  import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomEntry;
30  import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomFeed;
31  import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomLink;
32  import org.apache.chemistry.opencmis.client.bindings.spi.http.Output;
33  import org.apache.chemistry.opencmis.client.bindings.spi.http.Response;
34  import org.apache.chemistry.opencmis.commons.data.ExtensionsData;
35  import org.apache.chemistry.opencmis.commons.data.ObjectData;
36  import org.apache.chemistry.opencmis.commons.data.ObjectList;
37  import org.apache.chemistry.opencmis.commons.enums.CmisVersion;
38  import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
39  import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
40  import org.apache.chemistry.opencmis.commons.impl.Constants;
41  import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
42  import org.apache.chemistry.opencmis.commons.impl.XMLConverter;
43  import org.apache.chemistry.opencmis.commons.impl.XMLUtils;
44  import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectListImpl;
45  import org.apache.chemistry.opencmis.commons.impl.dataobjects.QueryTypeImpl;
46  import org.apache.chemistry.opencmis.commons.spi.DiscoveryService;
47  import org.apache.chemistry.opencmis.commons.spi.ExtendedHolder;
48  import org.apache.chemistry.opencmis.commons.spi.Holder;
49  
50  /**
51   * Discovery Service AtomPub client.
52   */
53  public class DiscoveryServiceImpl extends AbstractAtomPubService implements DiscoveryService {
54  
55      /**
56       * Constructor.
57       */
58      public DiscoveryServiceImpl(BindingSession session) {
59          setSession(session);
60      }
61  
62      @Override
63      public ObjectList getContentChanges(String repositoryId, Holder<String> changeLogToken, Boolean includeProperties,
64              String filter, Boolean includePolicyIds, Boolean includeACL, BigInteger maxItems, ExtensionsData extension) {
65          ObjectListImpl result = new ObjectListImpl();
66  
67          // find the link
68          String link = null;
69          UrlBuilder url = null;
70  
71          // if the application doesn't know the change log token but the link to
72          // the next Atom feed
73          if (changeLogToken instanceof ExtendedHolder && changeLogToken.getValue() == null) {
74              link = (String) ((ExtendedHolder<String>) changeLogToken).getExtraValue(Constants.REP_REL_CHANGES);
75              if (link != null) {
76                  url = new UrlBuilder(link);
77              }
78          }
79  
80          // if the application didn't provide a link to next Atom feed
81          if (link == null) {
82              link = loadRepositoryLink(repositoryId, Constants.REP_REL_CHANGES);
83              if (link != null) {
84                  url = new UrlBuilder(link);
85                  url.addParameter(Constants.PARAM_CHANGE_LOG_TOKEN,
86                          (changeLogToken == null ? null : changeLogToken.getValue()));
87                  url.addParameter(Constants.PARAM_PROPERTIES, includeProperties);
88                  url.addParameter(Constants.PARAM_FILTER, filter);
89                  url.addParameter(Constants.PARAM_POLICY_IDS, includePolicyIds);
90                  url.addParameter(Constants.PARAM_ACL, includeACL);
91                  url.addParameter(Constants.PARAM_MAX_ITEMS, maxItems);
92              }
93          }
94  
95          if (link == null) {
96              throw new CmisObjectNotFoundException("Unknown repository or content changes not supported!");
97          }
98  
99          // read and parse
100         Response resp = read(url);
101         AtomFeed feed = parse(resp.getStream(), AtomFeed.class);
102         String lastChangeLogToken = null;
103 
104         // handle top level
105         String nextLink = null;
106         for (AtomElement element : feed.getElements()) {
107             if (element.getObject() instanceof AtomLink) {
108                 if (isNextLink(element)) {
109                     result.setHasMoreItems(Boolean.TRUE);
110                     nextLink = ((AtomLink) element.getObject()).getHref();
111                 }
112             } else if (isInt(NAME_NUM_ITEMS, element)) {
113                 result.setNumItems((BigInteger) element.getObject());
114             } else if (isStr("changeLogToken", element)) {
115                 lastChangeLogToken = (String) element.getObject();
116             }
117         }
118 
119         // get the changes
120         if (!feed.getEntries().isEmpty()) {
121             result.setObjects(new ArrayList<ObjectData>(feed.getEntries().size()));
122 
123             for (AtomEntry entry : feed.getEntries()) {
124                 ObjectData hit = null;
125 
126                 // walk through the entry
127                 for (AtomElement element : entry.getElements()) {
128                     if (element.getObject() instanceof ObjectData) {
129                         hit = (ObjectData) element.getObject();
130                     }
131                 }
132 
133                 if (hit != null) {
134                     result.getObjects().add(hit);
135                 }
136             }
137         }
138 
139         if (changeLogToken != null) {
140             // the AtomPub binding cannot return a new change log token,
141             // but an OpenCMIS server uses a proprietary tag
142             changeLogToken.setValue(lastChangeLogToken);
143 
144             // but we can provide the link to the next Atom feed
145             if (changeLogToken instanceof ExtendedHolder && nextLink != null) {
146                 ((ExtendedHolder<String>) changeLogToken).setExtraValue(Constants.REP_REL_CHANGES, nextLink);
147             }
148         }
149 
150         return result;
151     }
152 
153     @Override
154     public ObjectList query(String repositoryId, String statement, Boolean searchAllVersions,
155             Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter,
156             BigInteger maxItems, BigInteger skipCount, ExtensionsData extension) {
157         ObjectListImpl result = new ObjectListImpl();
158 
159         // find the link
160         String link = loadCollection(repositoryId, Constants.COLLECTION_QUERY);
161 
162         if (link == null) {
163             throw new CmisObjectNotFoundException("Unknown repository or query not supported!");
164         }
165 
166         UrlBuilder url = new UrlBuilder(link);
167 
168         // compile query request
169         final QueryTypeImpl query = new QueryTypeImpl();
170         query.setStatement(statement);
171         query.setSearchAllVersions(searchAllVersions);
172         query.setIncludeAllowableActions(includeAllowableActions);
173         query.setIncludeRelationships(includeRelationships);
174         query.setRenditionFilter(renditionFilter);
175         query.setMaxItems(maxItems);
176         query.setSkipCount(skipCount);
177 
178         final CmisVersion cmisVersion = getCmisVersion(repositoryId);
179 
180         // post the query and parse results
181         Response resp = post(url, Constants.MEDIATYPE_QUERY, new Output() {
182             @Override
183             public void write(OutputStream out) throws Exception {
184                 XMLStreamWriter writer = XMLUtils.createWriter(out);
185                 XMLUtils.startXmlDocument(writer);
186                 XMLConverter.writeQuery(writer, cmisVersion, query);
187                 XMLUtils.endXmlDocument(writer);
188             }
189         });
190         AtomFeed feed = parse(resp.getStream(), AtomFeed.class);
191 
192         // handle top level
193         for (AtomElement element : feed.getElements()) {
194             if (element.getObject() instanceof AtomLink) {
195                 if (isNextLink(element)) {
196                     result.setHasMoreItems(Boolean.TRUE);
197                 }
198             } else if (isInt(NAME_NUM_ITEMS, element)) {
199                 result.setNumItems((BigInteger) element.getObject());
200             }
201         }
202 
203         // get the result set
204         if (!feed.getEntries().isEmpty()) {
205             result.setObjects(new ArrayList<ObjectData>(feed.getEntries().size()));
206 
207             for (AtomEntry entry : feed.getEntries()) {
208                 ObjectData hit = null;
209 
210                 // walk through the entry
211                 for (AtomElement element : entry.getElements()) {
212                     if (element.getObject() instanceof ObjectData) {
213                         hit = (ObjectData) element.getObject();
214                     }
215                 }
216 
217                 if (hit != null) {
218                     result.getObjects().add(hit);
219                 }
220             }
221         }
222 
223         return result;
224     }
225 }