001/*
002 * **** BEGIN LICENSE BLOCK *****
003 *  Version: MPL 1.1/GPL 2.0/LGPL 2.1
004 *
005 *  The contents of this file are subject to the Mozilla Public License Version
006 *  1.1 (the "License"); you may not use this file except in compliance with
007 *  the License. You may obtain a copy of the License at
008 *  http://www.mozilla.org/MPL/
009 *
010 *  Software distributed under the License is distributed on an "AS IS" basis,
011 *  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
012 *  for the specific language governing rights and limitations under the
013 *  License.
014 *
015 *  The Original Code is part of dcm4che, an implementation of DICOM(TM) in
016 *  Java(TM), hosted at https://github.com/gunterze/dcm4che.
017 *
018 *  The Initial Developer of the Original Code is
019 *  Agfa Healthcare.
020 *  Portions created by the Initial Developer are Copyright (C) 2014
021 *  the Initial Developer. All Rights Reserved.
022 *
023 *  Contributor(s):
024 *  See @authors listed below
025 *
026 *  Alternatively, the contents of this file may be used under the terms of
027 *  either the GNU General Public License Version 2 or later (the "GPL"), or
028 *  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
029 *  in which case the provisions of the GPL or the LGPL are applicable instead
030 *  of those above. If you wish to allow use of your version of this file only
031 *  under the terms of either the GPL or the LGPL, and not to allow others to
032 *  use your version of this file under the terms of the MPL, indicate your
033 *  decision by deleting the provisions above and replace them with the notice
034 *  and other provisions required by the GPL or the LGPL. If you do not delete
035 *  the provisions above, a recipient may use your version of this file under
036 *  the terms of any one of the MPL, the GPL or the LGPL.
037 *
038 *  ***** END LICENSE BLOCK *****
039 */
040package org.dcm4che3.conf.core.api;
041
042import java.util.Iterator;
043import java.util.Map;
044import java.util.TreeMap;
045
046/**
047 * Denotes a configuration source. Can be used by BeanVitalizer that creates POJOs, or configuration administration app that provides UI to edit configuration.
048 * <br/> <br/>
049 * The Configuration API operates on a tree data structure, where any subtree is referred to as a configuration node.
050 * A configuration node represents a JSON object. A configuration node is either
051 * <ul>
052 * <li> a primitive wrapper/string (Number, Boolean, String)</li>
053 * <li> null</li>
054 * <li> a collection of nodes </li>
055 * <li> Map&lt;String,Object&gt; where each object is a configuration node (single map can have values of multiple types.</li>
056 * </ul>
057 * Formally, if such a node object is serialized into JSON and back without any transformations applied, the resulting object should be deep-equal to the original one.
058 * <p/>
059 * A <i>path</i> is a valid XPath expression evaluated against the configuration tree. The usage of very advanced XPath expressions is not recommended, since it could lead to eager loading of configuration tree.
060 * Examples of paths can be found in org.dcm4che3.conf.dicom.DicomPath. A helper class org.dcm4che3.conf.core.util.PathPattern can be used to safely compose parametrized paths.
061 */
062public interface Configuration extends BatchRunner {
063
064    String CONF_STORAGE_SYSTEM_PROP = "org.dcm4che.conf.storage";
065
066    /**
067     * A special property key that indicates that this property is the referable uuid of the containing config node
068     */
069    String UUID_KEY = "_.uuid";
070
071    /**
072     * A special property key that indicates that
073     * the containing node is a hash-based optimistic locking root and
074     * that this property contains the hash of this node.
075     */
076    String OLOCK_HASH_KEY = "_.hash";
077
078    /**
079     * A special property key that indicates that the container of this property is a reference
080     * to a node with uuid that equals to the property's value.
081     * Additionally if WEAK_REFERENCE_KEY:true is defined in the container node,
082     * this reference is considered to be a weak reference ({@link ConfigurableProperty#weakReference()})
083     */
084    String REFERENCE_KEY = "_.ref";
085    String WEAK_REFERENCE_KEY = "weakReference";
086    String REFERENCE_BY_UUID_PATTERN = "//*[_.uuid='{uuid}']";
087
088
089    enum ConfigStorageType {
090        JSON_FILE,
091        DB_BLOBS;
092    }
093
094    /**
095     * Return the root of the configuration tree.
096     * The returned node should not be modified directly (only through persistNode/removeNode).
097     *
098     * @return configuration tree
099     * @throws ConfigurationException
100     */
101    Map<String, Object> getConfigurationRoot() throws ConfigurationException;
102
103    /**
104     * Loads a configuration node under the specified path.
105     *
106     * @param path              A reference to a node
107     * @param configurableClass
108     * @return configuration node or null, if not found
109     * @throws ConfigurationException
110     */
111    Object getConfigurationNode(Path path, Class configurableClass) throws ConfigurationException;
112
113    /**
114     * Tests if a node under the specified path exists.
115     *
116     * @param path
117     * @return
118     * @throws ConfigurationException
119     */
120    boolean nodeExists(Path path) throws ConfigurationException;
121
122    /**
123     * Persists the configuration node to the specified path.
124     * The path must exist (or at least all nodes but the last one).
125     * The property is created/fully overwritten, i.e. if there were any child nodes in the old root that are not present in the new node root, they will be deleted in the new tree.
126     *  @param path              path to the node
127     * @param configNode        configuration node to persist
128     * @param configurableClass class annotated with ConfigurableClass, ConfigurableProperty annotations that corresponds to this node.
129     */
130    void persistNode(Path path, Map<String, Object> configNode, Class configurableClass) throws ConfigurationException;
131
132    /**
133     * Invalidates any present cached state for the node
134     * It is imperative that some other nodes might also be refreshed during the operation.
135     * There is no guarantee whether the new version will be re-loaded lazily or eagerly
136     *
137     * @param path
138     */
139    void refreshNode(Path path) throws ConfigurationException;
140
141    /**
142     * Removes a configuration node under the specified path with all its children permanently
143     *
144     * @param path
145     */
146    void removeNode(Path path) throws ConfigurationException;
147
148
149    Path getPathByUUID(String uuid);
150
151
152    /**
153     * Performs a search on the configuration tree and returns an iterator to configuration nodes that satisfy the search criteria.
154     *
155     * @param liteXPathExpression Must be absolute path, no double slashes, no @attributes (only [attr=val] or [attr<>val])
156     */
157    Iterator search(String liteXPathExpression) throws IllegalArgumentException, ConfigurationException;
158
159    /**
160     * Aquire a global pessimistic lock (cluster-aware implementations should ensure that only a single node can aquire the lock at a time)
161     * Subsequent calls from the same transaction should not block.
162     * Should be auto-released on transaction commit/rollback.
163     */
164    void lock();
165
166
167    class NodeFactory {
168        public static Map<String,Object> emptyNode() {
169            return new TreeMap<String, Object>();
170        }
171    }
172}