]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
e573f9f638e4b10768119c3e60a44834c89a1098
[tmp/jakarta-migration.git] /
1 package org.collectionspace.services.nuxeo.client.java;
2
3 import java.io.UnsupportedEncodingException;
4 import java.net.URLDecoder;
5 import java.net.URLEncoder;
6 import java.security.Principal;
7 import java.time.Instant;
8 import java.time.LocalDateTime;
9 import java.time.ZoneId;
10 import java.time.ZonedDateTime;
11 import java.time.format.DateTimeFormatter;
12 import java.time.format.DateTimeParseException;
13 import java.util.regex.Matcher;
14 import java.util.regex.Pattern;
15
16 import org.collectionspace.services.common.document.DocumentException;
17 import org.nuxeo.ecm.core.api.ClientException;
18 import org.nuxeo.ecm.core.api.DocumentModel;
19 import org.nuxeo.ecm.core.api.DocumentModelList;
20 import org.nuxeo.ecm.core.api.DocumentRef;
21 import org.nuxeo.ecm.core.api.Filter;
22 import org.nuxeo.ecm.core.api.IterableQueryResult;
23 import org.nuxeo.ecm.core.api.event.DocumentEventTypes;
24 import org.nuxeo.ecm.core.api.impl.LifeCycleFilter;
25 import org.nuxeo.ecm.core.api.CoreSession;
26 import org.nuxeo.runtime.transaction.TransactionHelper;
27
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 public class CoreSessionWrapper implements CoreSessionInterface {
32
33         private CoreSession repoSession;
34         private boolean transactionSetForRollback = false;
35         
36     /** The logger. */
37     private static Logger logger = LoggerFactory.getLogger(CoreSessionWrapper.class);
38     
39     private void logQuery(String query) {
40         logger.debug(String.format("NXQL: %s", query));
41     }
42     
43     private void logQuery(String query, String queryType) {
44         logger.debug(String.format("Query Type: '%s' NXQL: %s", queryType, query));
45     }
46     
47     private void logQuery(String query, Filter filter, long limit,
48                 long offset, boolean countTotal) {
49         logger.debug(String.format("Filter: '%s', Limit: '%d', Offset: '%d', Count Total?: %b, NXQL: %s",
50                         filter != null ? filter.toString() : "none", limit, offset, countTotal, query));
51     }
52     
53         public CoreSessionWrapper(CoreSession repoSession) {
54                 this.repoSession = repoSession;
55         }
56
57         /*
58          * Mark this session's transaction for rollback only
59          */
60         @Override
61     public void setTransactionRollbackOnly() {
62                 TransactionHelper.setTransactionRollbackOnly();
63         transactionSetForRollback = true;
64     }
65         
66         @Override
67     public boolean isTransactionMarkedForRollbackOnly() {
68                 if (transactionSetForRollback != TransactionHelper.isTransactionMarkedRollback()) {
69                         logger.error(String.format("Transaction status is in an inconsistent state.  Internal state is '%b'.  TransactionHelper statis is '%b'.",
70                                         transactionSetForRollback, TransactionHelper.isTransactionMarkedRollback()));
71                 }
72         return transactionSetForRollback;
73     }
74         
75         @Override
76         public  CoreSession getCoreSession() {
77                 return repoSession;
78         }
79         
80         @Override
81     public String getSessionId() {
82         return repoSession.getSessionId();
83     }
84     
85     @Override
86     public void close() throws Exception {
87         try {
88                 repoSession.close();
89         } catch (Throwable t) {
90                 logger.error(String.format("Could not close session for repository '%s'.", this.repoSession.getRepositoryName()),
91                                 t);
92         }
93     }
94
95     /**
96      * Gets the root document of this repository.
97      *
98      * @return the root document. cannot be null
99      * @throws ClientException
100      * @throws SecurityException
101      */
102         @Override
103     public DocumentModel getRootDocument() throws ClientException {
104         return repoSession.getRootDocument();
105     }
106     
107     /**
108      * Returns the repository name against which this core session is bound.
109      *
110      * @return the repository name used currently used as an identifier
111      */
112         @Override
113     public String getRepositoryName() {
114                 return repoSession.getRepositoryName();
115         }
116     
117     /**
118      * Gets the principal that created the client session.
119      *
120      * @return the principal
121      */
122         @Override
123         public Principal getPrincipal() {
124                 return repoSession.getPrincipal();
125         }
126         
127         private String toLocalTimestamp(String utcTime, boolean base64Encoded) throws DocumentException {
128                 String result = null;
129
130                 try {
131                         if (base64Encoded == true) {
132                                 utcTime = URLDecoder.decode(utcTime, java.nio.charset.StandardCharsets.UTF_8.name());
133                         }
134                         LocalDateTime localTime;
135                         try {
136                                 Instant instant = Instant.parse(utcTime);
137                                 ZonedDateTime localInstant = instant.atZone(ZoneId.systemDefault()); // DateTimeFormatter.ISO_LOCAL_DATE_TIME
138                                 localTime = localInstant.toLocalDateTime();
139                         } catch (DateTimeParseException e) {
140                                 localTime = LocalDateTime.parse(utcTime, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
141                         }
142                         result = localTime.toString();
143                         if (base64Encoded == true) {
144                                 result = URLEncoder.encode(result, java.nio.charset.StandardCharsets.UTF_8.name());
145                         }
146                 } catch (UnsupportedEncodingException e) {
147                         throw new DocumentException(e);
148                 }
149                 
150                 return result;
151         }
152         
153         private String localizeTimestamps(String query) throws DocumentException {
154                 String result = query;
155                 
156                 if (query.contains("TIMESTAMP")) {
157                         StringBuffer stringBuffer = new StringBuffer();
158                         Pattern pattern = Pattern.compile("\\+TIMESTAMP\\+%22(.+?)%22");
159                         Matcher matcher = pattern.matcher(query);
160                         while (matcher.find()) {
161                                 String time = matcher.group(1);
162                                 String localizedTime = toLocalTimestamp(time, true);
163                                 matcher.appendReplacement(stringBuffer, String.format("+TIMESTAMP+%%22%s%%22", localizedTime));
164                         }
165                         matcher.appendTail(stringBuffer);
166                         result = stringBuffer.toString();
167                 }
168                 
169                 return result;
170         }
171
172         @Override
173         public IterableQueryResult queryAndFetch(String query, String queryType,
174             Object... params) throws ClientException, DocumentException {
175                 query = localizeTimestamps(query);
176                 logQuery(query, queryType);
177                 return repoSession.queryAndFetch(query, queryType, params);
178         }
179
180         @Override
181         public DocumentModelList query(String query, Filter filter, long limit,
182             long offset, boolean countTotal) throws ClientException, DocumentException {
183                 query = localizeTimestamps(query);
184                 logQuery(query, filter, limit, offset, countTotal);
185                 return repoSession.query(query, filter, limit, offset, countTotal);
186         }
187
188         @Override
189     public DocumentModelList query(String query, int max) throws ClientException, DocumentException {
190                 query = localizeTimestamps(query);
191                 logQuery(query);
192         return repoSession.query(query, max);
193     }
194     
195         @Override
196         public DocumentModelList query(String query) throws ClientException, DocumentException {
197                 query = localizeTimestamps(query);
198                 logQuery(query);
199                 return repoSession.query(query);
200         }
201         
202         @Override
203         public DocumentModelList query(String query, LifeCycleFilter workflowStateFilter) throws DocumentException {
204                 query = localizeTimestamps(query);
205                 return repoSession.query(query, workflowStateFilter);
206         }
207
208     /**
209      * Gets a document model given its reference.
210      * <p>
211      * The default schemas are used to populate the returned document model.
212      * Default schemas are configured via the document type manager.
213      * <p>
214      * Any other data model not part of the default schemas will be lazily
215      * loaded as needed.
216      *
217      * @param docRef the document reference
218      * @return the document
219      * @throws ClientException
220      * @throws SecurityException
221      */
222     @Override
223     public DocumentModel getDocument(DocumentRef docRef) throws ClientException {
224             return repoSession.getDocument(docRef);
225     }
226
227     @Override
228     public DocumentModel saveDocument(DocumentModel docModel) throws ClientException {
229         DocumentModel result = null;
230         
231         try {
232                 if (isTransactionMarkedForRollbackOnly() == false) {
233                         result = repoSession.saveDocument(docModel);
234                 } else {
235                         logger.trace(String.format("The repository session on thread '%d' has a transaction that is marked for rollback.",
236                                         Thread.currentThread().getId()));
237                 }
238         } catch (Throwable t) {
239                 setTransactionRollbackOnly();
240                 throw t;
241         }
242         
243         return result;
244     }
245
246     @Override
247     public void save() throws ClientException {
248         try {
249                 if (isTransactionMarkedForRollbackOnly() == false) {
250                         repoSession.save();
251                 } else {
252                         logger.trace(String.format("The repository session on thread '%d' has a transaction that is marked for rollback.",
253                                         Thread.currentThread().getId()));
254                 }
255         } catch (Throwable t) {
256                 setTransactionRollbackOnly();
257                 throw t;
258         }
259     }
260
261     /**
262      * Bulk document saving.
263      *
264      * @param docModels the document models that needs to be saved
265      * @throws ClientException
266      */
267     @Override
268     public void saveDocuments(DocumentModel[] docModels) throws ClientException {
269         try {
270                 if (isTransactionMarkedForRollbackOnly() == false) {
271                         repoSession.saveDocuments(docModels);
272                 } else {
273                         logger.trace(String.format("The repository session on thread '%d' has a transaction that is marked for rollback.",
274                                         Thread.currentThread().getId()));
275                 }
276         } catch (Throwable t) {
277                 setTransactionRollbackOnly();
278                 throw t;
279         }
280     }
281
282     /**
283      * Removes this document and all its children, if any.
284      *
285      * @param docRef the reference to the document to remove
286      * @throws ClientException
287      */
288     @Override
289     public void removeDocument(DocumentRef docRef) throws ClientException {
290         repoSession.removeDocument(docRef);
291     }
292
293     /**
294      * Creates a document model using required information.
295      * <p>
296      * Used to fetch initial datamodels from the type definition.
297      * <p>
298      * DocumentModel creation notifies a
299      * {@link DocumentEventTypes.EMPTY_DOCUMENTMODEL_CREATED} so that core event
300      * listener can initialize its content with computed properties.
301      *
302      * @param parentPath
303      * @param id
304      * @param typeName
305      * @return the initial document model
306      * @throws ClientException
307      */
308     @Override
309     public DocumentModel createDocumentModel(String parentPath, String id,
310             String typeName) throws ClientException {
311         return repoSession.createDocumentModel(parentPath, id, typeName);
312     }
313     
314     /**
315      * Creates a document using given document model for initialization.
316      * <p>
317      * The model contains path of the new document, its type and optionally the
318      * initial data models of the document.
319      * <p>
320      *
321      * @param model the document model to use for initialization
322      * @return the created document
323      * @throws ClientException
324      */
325     @Override
326     public DocumentModel createDocument(DocumentModel model) throws ClientException {
327         return repoSession.createDocument(model);
328     }
329     
330     /**
331      * Gets the children of the given parent.
332      *
333      * @param parent the parent reference
334      * @return the children if any, an empty list if no children or null if the
335      *         specified parent document is not a folder
336      * @throws ClientException
337      */
338     @Override
339     public DocumentModelList getChildren(DocumentRef parent) throws ClientException {
340         return repoSession.getChildren(parent);
341     }
342
343     
344         
345 }