001/*
002 * (C) Copyright 2006-2019 Nuxeo (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Florent Guillaume
018 */
019package org.nuxeo.ecm.core.storage.sql;
020
021import java.io.Serializable;
022import java.util.Collection;
023import java.util.List;
024import java.util.Map;
025import java.util.function.Consumer;
026
027import org.nuxeo.ecm.core.api.IterableQueryResult;
028import org.nuxeo.ecm.core.api.PartialList;
029import org.nuxeo.ecm.core.api.ScrollResult;
030import org.nuxeo.ecm.core.api.lock.LockManager;
031import org.nuxeo.ecm.core.model.Document;
032import org.nuxeo.ecm.core.query.QueryFilter;
033
034/**
035 * The session is the main high level access point to data from the underlying database.
036 *
037 * @author Florent Guillaume
038 */
039public interface Session extends AutoCloseable {
040
041    @Override
042    void close();
043
044    /**
045     * Gets the low-level Mapper for this session.
046     *
047     * @return the mapper
048     */
049    Mapper getMapper();
050
051    /**
052     * Gets the session repository name.
053     *
054     * @return the repository name
055     */
056    String getRepositoryName();
057
058    /**
059     * Gets the {@link Model} associated to this session.
060     *
061     * @return the model
062     */
063    Model getModel();
064
065    /**
066     * Saves the modifications to persistent storage.
067     * <p>
068     * Modifications will be actually written only upon transaction commit.
069     */
070    void save();
071
072    /**
073     * Gets the root node of the repository.
074     *
075     * @return the root node
076     */
077    Node getRootNode();
078
079    /**
080     * Gets a node given its id.
081     *
082     * @param id the id
083     * @return the node, or {@code null} if not found
084     */
085    Node getNodeById(Serializable id);
086
087    /**
088     * Gets several nodes given their ids.
089     *
090     * @param ids the ids
091     * @return the nodes, in the same order as the ids, with elements being {@code null} if not found
092     */
093    List<Node> getNodesByIds(Collection<Serializable> ids);
094
095    /**
096     * Gets a node given its absolute path, or given an existing node and a relative path.
097     *
098     * @param path the path
099     * @param node the node (ignored for absolute paths)
100     * @return the node, or {@code null} if not found
101     */
102    Node getNodeByPath(String path, Node node);
103
104    /**
105     * Adds a mixin to a node.
106     * <p>
107     * Does nothing if the mixin was already present on the node.
108     *
109     * @param node the node
110     * @param mixin the mixin name
111     * @return {@code true} if the mixin was added, or {@code false} if it is already present
112     * @since 5.8
113     */
114    boolean addMixinType(Node node, String mixin);
115
116    /**
117     * Removes a mixin from a node.
118     * <p>
119     * It's not possible to remove a mixin coming from the primary type.
120     *
121     * @param node the node
122     * @param mixin the mixin
123     * @return {@code true} if the mixin was removed, or {@code false} if it isn't present or is present on the type or
124     *         does not exist
125     * @since 5.8
126     */
127    boolean removeMixinType(Node node, String mixin);
128
129    /**
130     * Executes the given query and returns the first batch of results containing id of documents, next batch must be
131     * requested within the {@code keepAliveSeconds} delay.
132     *
133     * @since 8.4
134     */
135    ScrollResult<String> scroll(String query, int batchSize, int keepAliveSeconds);
136
137    /**
138     * Executes the given query and returns the first batch of results containing id of documents, next batch must be
139     * requested within the {@code keepAliveSeconds} delay.
140     *
141     * @since 10.3
142     */
143    ScrollResult<String> scroll(String query, QueryFilter queryFilter, int batchSize, int keepAliveSeconds);
144
145    /**
146     * Get the next batch of results containing id of documents, the {@code scrollId} is part of the previous
147     * {@link ScrollResult} response.
148     *
149     * @since 8.4
150     */
151    ScrollResult<String> scroll(String scrollId);
152
153    /**
154     * Interface for a class that knows how to resolve a node path into a node id.
155     */
156    interface PathResolver {
157        /**
158         * Returns the node id for a given path.
159         *
160         * @param path the node path
161         * @return the node id, or {@code null}
162         */
163        Serializable getIdForPath(String path);
164    }
165
166    /**
167     * Gets the parent of a node.
168     * <p>
169     * The root has a {@code null} parent.
170     *
171     * @param node the node
172     * @return the parent node, or {@code null} for the root's parent
173     */
174    Node getParentNode(Node node);
175
176    /**
177     * Gets the absolute path of a node.
178     *
179     * @param node the node
180     * @return the path
181     */
182    String getPath(Node node);
183
184    /**
185     * Checks if a child node with the given name exists.
186     * <p>
187     * There are two kinds of children, the regular children documents and the complex properties. The {@code boolean}
188     * {@code complexProp} allows a choice between those.
189     *
190     * @param parent the parent node
191     * @param name the child name
192     * @param complexProp whether to check complex properties or regular children
193     * @return {@code true} if a child node with that name exists
194     */
195    boolean hasChildNode(Node parent, String name, boolean complexProp);
196
197    /**
198     * Gets a child node given its parent and name.
199     *
200     * @param parent the parent node
201     * @param name the child name
202     * @param complexProp whether to check complex properties or regular children
203     * @return the child node, or {@code null} is not found
204     */
205    Node getChildNode(Node parent, String name, boolean complexProp);
206
207    /**
208     * Checks it a node has children.
209     *
210     * @param parent the parent node
211     * @param complexProp whether to check complex properties or regular children
212     * @return {@code true} if the parent has children
213     */
214    boolean hasChildren(Node parent, boolean complexProp);
215
216    /**
217     * Gets the children of a node.
218     *
219     * @param parent the parent node
220     * @param name the children name to get (for lists of complex properties), or {@code null} for all
221     * @param complexProp whether to check complex properties or regular children
222     * @return the collection of children
223     */
224    List<Node> getChildren(Node parent, String name, boolean complexProp);
225
226    /**
227     * Creates a new child node.
228     *
229     * @param parent the parent to which the child is added
230     * @param name the child name
231     * @param pos the child position, or {@code null}
232     * @param typeName the child type
233     * @param complexProp whether this is a complex property ({@code true}) or a regular child ({@code false})
234     * @return the new node
235     */
236    Node addChildNode(Node parent, String name, Long pos, String typeName, boolean complexProp);
237
238    /**
239     * Creates a new child node with given id (used for import).
240     *
241     * @param id the id
242     * @param parent the parent to which the child is added
243     * @param name the child name
244     * @param pos the child position, or {@code null}
245     * @param typeName the child type
246     * @param complexProp whether this is a complex property ({@code true}) or a regular child ({@code false})
247     * @return the new node
248     */
249    Node addChildNode(Serializable id, Node parent, String name, Long pos, String typeName, boolean complexProp);
250
251    /**
252     * Creates a proxy for a version node.
253     *
254     * @param targetId the target id
255     * @param versionSeriesId the version series id
256     * @param parent the parent to which the proxy is added
257     * @param name the proxy name
258     * @param pos the proxy position
259     * @return the new proxy node
260     */
261    Node addProxy(Serializable targetId, Serializable versionSeriesId, Node parent, String name, Long pos);
262
263    /**
264     * Sets a proxies' target.
265     *
266     * @param proxy the proxy
267     * @param targetId the new target id
268     * @since 5.5
269     */
270    void setProxyTarget(Node proxy, Serializable targetId);
271
272    /**
273     * Removes a node from the storage.
274     * <p>
275     * This is much more complex that removing a property node ( {@link #removePropertyNode}).
276     *
277     * @param node the node to remove
278     * @see #removePropertyNode
279     */
280    default void removeNode(Node node) {
281        removeNode(node, null);
282    }
283
284    /**
285     * Removes a node from the storage.
286     * <p>
287     * This is much more complex than removing a property node ({@link #removePropertyNode}).
288     *
289     * @param node the node to remove
290     * @param beforeRecordRemove a consumer called on nodes of records before they are removed
291     * @see #removePropertyNode
292     * @since 11.1
293     */
294    void removeNode(Node node, Consumer<Node> beforeRecordRemove);
295
296    /**
297     * Removes a property node from the storage.
298     * <p>
299     * This is much less complex that removing a generic document node ( {@link #removeNode}).
300     *
301     * @param node the property node to remove
302     * @see #removeNode
303     */
304    void removePropertyNode(Node node);
305
306    /**
307     * Order the given source child node before the destination child node. The source node will be placed before the
308     * destination one. If destination is {@code null}, the source node will be appended at the end of the children
309     * list.
310     *
311     * @param parent the parent node
312     * @param source the child node to move
313     * @param dest the child node before which to place the source node, or {@code null} to move at the end
314     */
315    void orderBefore(Node parent, Node source, Node dest);
316
317    /**
318     * Moves a node to a new location with a new name.
319     * <p>
320     * A {@link #save} is automatically done first.
321     *
322     * @param source the node to move
323     * @param parent the new parent to which the node is moved
324     * @param name the new node name
325     * @return the moved node
326     */
327    Node move(Node source, Node parent, String name);
328
329    /**
330     * Copies a node to a new location with a new name.
331     * <p>
332     * A {@link #save} is automatically done first.
333     *
334     * @param source the node to copy
335     * @param parent the new parent to which the node is copied
336     * @param name the new node name
337     * @return the copied node
338     */
339    default Node copy(Node source, Node parent, String name) {
340        return copy(source, parent, name, null);
341    }
342
343    /**
344     * Copies a node to a new location with a new name.
345     * <p>
346     * A {@link #save} is automatically done first.
347     *
348     * @param source the node to copy
349     * @param parent the new parent to which the node is copied
350     * @param name the new node name
351     * @param afterRecordCopy a consumer called on nodes that were records before copy
352     * @return the copied node
353     * @since 11.1
354     */
355    Node copy(Node source, Node parent, String name, Consumer<Node> afterRecordCopy);
356
357    /**
358     * Checks in a checked-out node: creates a new version with a copy of its information.
359     * <p>
360     * A {@link #save} is automatically done first.
361     *
362     * @param node the node to check in
363     * @param label the label for the version
364     * @param checkinComment the description for the version
365     * @return the created version
366     */
367    Node checkIn(Node node, String label, String checkinComment);
368
369    /**
370     * Checks out a checked-in node.
371     *
372     * @param node the node to check out
373     */
374    void checkOut(Node node);
375
376    /**
377     * Restores a node to a given version.
378     * <p>
379     * The restored node is checked in.
380     *
381     * @param node the node to restore
382     * @param version the version to restore from
383     */
384    void restore(Node node, Node version);
385
386    /**
387     * Gets a version given its version series id and label.
388     *
389     * @param versionSeriesId the version series id
390     * @param label the label
391     * @return the version node, or {@code null} if not found
392     */
393    Node getVersionByLabel(Serializable versionSeriesId, String label);
394
395    /**
396     * Gets all the versions for a given version series id.
397     * <p>
398     * A {@link #save} is automatically done first.
399     *
400     * @param versionSeriesId the version series id
401     * @return the list of versions
402     */
403    List<Node> getVersions(Serializable versionSeriesId);
404
405    /**
406     * Gets the last version for a given version series id.
407     * <p>
408     * A {@link #save} is automatically done first.
409     *
410     * @param versionSeriesId the version series id
411     * @return the last version, or {@code null} if no versions exist
412     */
413    Node getLastVersion(Serializable versionSeriesId);
414
415    /**
416     * Finds the proxies for a document. If the parent is not null, the search will be limited to its direct children.
417     * <p>
418     * If the document is a version, then only proxies to that version will be looked up.
419     * <p>
420     * Otherwise all proxies to the same version series than the document are retrieved.
421     * <p>
422     * A {@link #save} is automatically done first.
423     *
424     * @param document the document
425     * @param parent the parent, or {@code null}
426     * @return the list of proxies
427     */
428    List<Node> getProxies(Node document, Node parent);
429
430    /**
431     * Finds the proxies for a document. (The document may be a version or a live document)
432     * @param document the document
433     * @return the list of proxies,  or an empty list
434     * @since 10.2
435     */
436    List<Node> getProxies(Node document);
437
438    /**
439     * Makes a NXQL query to the database.
440     *
441     * @param query the query
442     * @param queryFilter the query filter
443     * @param countTotal if {@code true}, also count the total size without offset/limit
444     * @return the resulting list with total size included
445     */
446    PartialList<Serializable> query(String query, QueryFilter queryFilter, boolean countTotal);
447
448    /**
449     * Makes a query to the database.
450     *
451     * @param query the query
452     * @param queryType the query type
453     * @param queryFilter the query filter
454     * @param countUpTo if {@code -1}, also count the total size without offset/limit.<br>
455     *            If {@code 0}, don't count the total size.<br>
456     *            If {@code n}, count the total number if there are less than n documents otherwise set the size to
457     *            {@code -1}.
458     * @return the resulting list with total size included
459     * @since 5.6
460     */
461    PartialList<Serializable> query(String query, String queryType, QueryFilter queryFilter, long countUpTo);
462
463    /**
464     * Makes a query to the database and returns an iterable (which must be closed when done).
465     *
466     * @param query the query
467     * @param queryType the query type
468     * @param queryFilter the query filter
469     * @param params optional query-type-dependent parameters
470     * @return an iterable, which <b>must</b> be closed when done
471     */
472    IterableQueryResult queryAndFetch(String query, String queryType, QueryFilter queryFilter, Object... params);
473
474    /**
475     * Makes a query to the database and returns an iterable (which must be closed when done).
476     *
477     * @param query the query
478     * @param queryType the query type
479     * @param queryFilter the query filter
480     * @param distinctDocuments if {@code true} then a maximum of one row per document will be returned
481     * @param params optional query-type-dependent parameters
482     * @return an iterable, which <b>must</b> be closed when done
483     * @since 7.10-HF04, 8.2
484     */
485    IterableQueryResult queryAndFetch(String query, String queryType, QueryFilter queryFilter,
486            boolean distinctDocuments, Object... params);
487
488    /**
489     * Makes a query to the database.
490     *
491     * @param query the query
492     * @param queryType the query type
493     * @param queryFilter the query filter
494     * @param distinctDocuments if {@code true} then a maximum of one row per document will be returned
495     * @param countUpTo if {@code -1}, also count the total size without offset/limit.<br>
496     *            If {@code 0}, don't count the total size.<br>
497     *            If {@code n}, count the total number if there are less than n documents otherwise set the size to
498     *            {@code -1}.
499     * @param params optional query-type-dependent parameters
500     * @return a projection
501     * @since 7.10-HF-25, 8.10-HF06, 9.2
502     */
503    PartialList<Map<String,Serializable>> queryProjection(String query, String queryType, QueryFilter queryFilter, boolean distinctDocuments,
504            long countUpTo, Object[] params);
505
506    /**
507     * Gets the lock manager for this session.
508     *
509     * @return the lock manager
510     * @since 7.4
511     */
512    LockManager getLockManager();
513
514    /**
515     * Read ACLs are optimized ACLs for the read permission, they need to be updated after document creation or ACL
516     * change.
517     * <p>
518     * This method flag the current session, the read ACLs update will be done automatically at save time.
519     */
520    void requireReadAclsUpdate();
521
522    /**
523     * Update only the read ACLs that have changed.
524     */
525    void updateReadAcls();
526
527    /**
528     * Rebuild the read ACLs for the whole repository.
529     */
530    void rebuildReadAcls();
531
532    /**
533     * Checks if fulltext extracted from the binary fields is internally stored as a blob.
534     *
535     * @return {@code true} if fulltext from binaries is store as a blob
536     * @since 11.1
537     */
538    boolean isFulltextStoredInBlob();
539
540    /**
541     * Gets the fulltext extracted from the binary fields.
542     *
543     * @since 11.1
544     */
545    Map<String, String> getBinaryFulltext(Serializable id, Document doc);
546
547    /**
548     * Gets the fulltext extracted from the binary fields.
549     *
550     * @since 5.9.3
551     * @deprecated since 11.1, use {@link #getBinaryFulltext(Serializable, Document)} instead
552     */
553    @Deprecated
554    default Map<String, String> getBinaryFulltext(Serializable id) {
555        return getBinaryFulltext(id, null);
556    }
557
558    /**
559     * Checks if change token management is enabled.
560     *
561     * @since 9.1
562     */
563    boolean isChangeTokenEnabled();
564
565    /**
566     * Marks the document as being modified by a user change.
567     * <p>
568     * This causes an additional change token increment and check during save.
569     *
570     * @param id the document id
571     * @since 9.2
572     */
573    void markUserChange(Serializable id);
574
575}