001/* ***** BEGIN LICENSE BLOCK *****
002 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
003 *
004 * The contents of this file are subject to the Mozilla Public License Version
005 * 1.1 (the "License"); you may not use this file except in compliance with
006 * the License. You may obtain a copy of the License at
007 * http://www.mozilla.org/MPL/
008 *
009 * Software distributed under the License is distributed on an "AS IS" basis,
010 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
011 * for the specific language governing rights and limitations under the
012 * License.
013 *
014 * The Original Code is part of dcm4che, an implementation of DICOM(TM) in
015 * Java(TM), hosted at https://github.com/gunterze/dcm4che.
016 *
017 * The Initial Developer of the Original Code is
018 * Agfa Healthcare.
019 * Portions created by the Initial Developer are Copyright (C) 2011-2014
020 * the Initial Developer. All Rights Reserved.
021 *
022 * Contributor(s):
023 * See @authors listed below
024 *
025 * Alternatively, the contents of this file may be used under the terms of
026 * either the GNU General Public License Version 2 or later (the "GPL"), or
027 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
028 * in which case the provisions of the GPL or the LGPL are applicable instead
029 * of those above. If you wish to allow use of your version of this file only
030 * under the terms of either the GPL or the LGPL, and not to allow others to
031 * use your version of this file under the terms of the MPL, indicate your
032 * decision by deleting the provisions above and replace them with the notice
033 * and other provisions required by the GPL or the LGPL. If you do not delete
034 * the provisions above, a recipient may use your version of this file under
035 * the terms of any one of the MPL, the GPL or the LGPL.
036 *
037 * ***** END LICENSE BLOCK ***** */
038
039package org.dcm4che3.conf.dicom;
040
041import org.dcm4che3.conf.ConfigurationSettingsLoader;
042import org.dcm4che3.conf.core.DefaultBeanVitalizer;
043import org.dcm4che3.conf.core.ExtensionMergingConfiguration;
044import org.dcm4che3.conf.core.api.Configuration;
045import org.dcm4che3.conf.core.api.ConfigurationException;
046import org.dcm4che3.conf.core.api.Path;
047import org.dcm4che3.conf.core.index.ReferenceIndexingDecorator;
048import org.dcm4che3.conf.core.normalization.DefaultsAndNullFilterDecorator;
049import org.dcm4che3.conf.core.olock.HashBasedOptimisticLockingConfiguration;
050import org.dcm4che3.conf.core.storage.SimpleCachingConfigurationDecorator;
051import org.dcm4che3.conf.core.storage.SingleJsonFileConfigurationStorage;
052import org.dcm4che3.net.AEExtension;
053import org.dcm4che3.net.DeviceExtension;
054import org.dcm4che3.net.hl7.HL7ApplicationExtension;
055import org.slf4j.Logger;
056import org.slf4j.LoggerFactory;
057
058import java.util.*;
059
060/**
061 * @author Gunter Zeilinger <gunterze@gmail.com>
062 */
063public class DicomConfigurationBuilder {
064
065    private Hashtable<?, ?> props;
066
067    private static Logger LOG = LoggerFactory
068            .getLogger(DicomConfigurationBuilder.class);
069
070    private boolean extensionMerge = false;
071    private boolean cache = false;
072    private Hashtable<?, ?> ldapProps = null;
073    private Configuration configurationStorage = null;
074    private Map<Class, List<Class>> extensionClassesMap = new HashMap<Class, List<Class>>();
075    private boolean doOptimisticLocking = false;
076    private boolean uuidIndexing = true;
077
078    private void setLdapProps(Hashtable<?, ?> ldapProps) {
079        this.ldapProps = ldapProps;
080    }
081
082    public DicomConfigurationBuilder() {
083        this.props = new Hashtable<Object, Object>();
084    }
085
086    public DicomConfigurationBuilder(Hashtable<?, ?> props) {
087        this.props = props;
088    }
089
090    public DicomConfigurationBuilder registerCustomConfigurationStorage(Configuration storage) {
091        configurationStorage = storage;
092        return this;
093    }
094
095
096    public DicomConfigurationBuilder registerExtensionForBaseExtension(Class extensionClass, Class baseExtensionClass) {
097
098        List<Class> extensionClasses = extensionClassesMap.get(baseExtensionClass);
099
100        if (extensionClasses == null) {
101            extensionClasses = new ArrayList<Class>();
102            extensionClassesMap.put(baseExtensionClass, extensionClasses);
103        }
104
105        // don't put duplicates
106        if (!extensionClasses.contains(extensionClass))
107            extensionClasses.add(extensionClass);
108
109        return this;
110    }
111
112    public <T extends DeviceExtension> DicomConfigurationBuilder registerDeviceExtension(
113            Class<T> clazz) {
114        registerExtensionForBaseExtension(clazz, DeviceExtension.class);
115        return this;
116    }
117
118    public <T extends AEExtension> DicomConfigurationBuilder registerAEExtension(
119            Class<T> clazz) {
120        registerExtensionForBaseExtension(clazz, AEExtension.class);
121        return this;
122    }
123
124    public <T extends HL7ApplicationExtension> DicomConfigurationBuilder registerHL7ApplicationExtension(
125            Class<T> clazz) {
126        registerExtensionForBaseExtension(clazz, HL7ApplicationExtension.class);
127        return this;
128    }
129
130    public DicomConfigurationBuilder extensionMerge(boolean extensionMerge) {
131        this.extensionMerge = extensionMerge;
132        return this;
133    }
134
135    public DicomConfigurationBuilder cache(boolean cache) {
136        this.cache = cache;
137        return this;
138    }
139
140
141    public DicomConfigurationBuilder uuidIndexing() {
142        this.uuidIndexing = true;
143        return this;
144    }
145
146    public DicomConfigurationBuilder disableUuidIndexing() {
147        this.uuidIndexing = false;
148        return this;
149    }
150
151    public CommonDicomConfigurationWithHL7 build() throws ConfigurationException {
152
153        List<Class> allExtensions = new ArrayList<Class>();
154
155        for (Map.Entry<Class, List<Class>> classListEntry : extensionClassesMap.entrySet())
156            allExtensions.addAll(classListEntry.getValue());
157
158        Configuration configurationStorage = createConfigurationStorage(allExtensions);
159        if (configurationStorage == null) return null;
160
161
162        for (Map.Entry<Class, List<Class>> classListEntry : extensionClassesMap.entrySet())
163            LOG.info("Dcm4che configuration {} classes: {}", classListEntry.getKey().getSimpleName(), classListEntry.getValue());
164
165
166        // check if we have any extensions that have equal simple name and fail if found
167        HashSet<String> simpleNames = new HashSet<String>();
168        for (Class extension : allExtensions) {
169            if (!simpleNames.add(extension.getSimpleName()))
170
171                throw new ConfigurationException(
172                        "Duplicate configuration class extension name '"
173                                + extension.getSimpleName()
174                                + "'. Make sure that simple class names of extensions are unique!");
175        }
176
177
178        return new CommonDicomConfigurationWithHL7(configurationStorage, extensionClassesMap);
179    }
180
181    protected Configuration createConfigurationStorage(List<Class> allExtensions) throws ConfigurationException {
182
183        // if configurationStorage is already set - skip the storage init
184        if (configurationStorage == null) {
185            String configType = ConfigurationSettingsLoader.getPropertyWithNotice(props,
186                    Configuration.CONF_STORAGE_SYSTEM_PROP, "json_file",
187                    " Possible values: 'json_file'.");
188
189            switch (Configuration.ConfigStorageType.valueOf(configType.toUpperCase().trim())) {
190                case JSON_FILE:
191                    SingleJsonFileConfigurationStorage jsonConfigurationStorage = createJsonFileConfigurationStorage();
192                    jsonConfigurationStorage.configure(props);
193                    configurationStorage = jsonConfigurationStorage;
194                    break;
195                default:
196                    throw new RuntimeException("Not implemented");
197            }
198        }
199
200        if (cache)
201            configurationStorage = new SimpleCachingConfigurationDecorator(configurationStorage, props);
202
203        if(extensionMerge)
204            configurationStorage = new ExtensionMergingConfiguration(configurationStorage, allExtensions);
205
206        if (uuidIndexing)
207            configurationStorage = new ReferenceIndexingDecorator(configurationStorage, new HashMap<String, Path>());
208
209        if (doOptimisticLocking)
210            configurationStorage = new HashBasedOptimisticLockingConfiguration(configurationStorage, allExtensions);
211
212        configurationStorage = new DefaultsAndNullFilterDecorator(
213                configurationStorage,
214                allExtensions,
215                CommonDicomConfiguration.createDefaultDicomVitalizer()
216        );
217
218        return configurationStorage;
219    }
220
221    protected SingleJsonFileConfigurationStorage createJsonFileConfigurationStorage() {
222        return new SingleJsonFileConfigurationStorage();
223    }
224
225    public static DicomConfigurationBuilder newConfigurationBuilder(Hashtable<?, ?> props)
226            throws ConfigurationException {
227        return new DicomConfigurationBuilder(props);
228    }
229
230    public static DicomConfigurationBuilder newJsonConfigurationBuilder(String fileName) {
231        Hashtable<Object, Object> props = new Hashtable<Object, Object>();
232        props.put("org.dcm4che.conf.storage", "json_file");
233        props.put("org.dcm4che.conf.filename", fileName);
234        return new DicomConfigurationBuilder(props);
235    }
236
237    @Deprecated
238    public static DicomConfigurationBuilder newLdapConfigurationBuilder(Hashtable<?, ?> ldapProps)
239            throws ConfigurationException {
240        Hashtable<Object, Object> props = new Hashtable<Object, Object>();
241        props.put("org.dcm4che.conf.storage", "ldap");
242        DicomConfigurationBuilder dicomConfigurationBuilder = new DicomConfigurationBuilder(props);
243        dicomConfigurationBuilder.setLdapProps(ldapProps);
244        return dicomConfigurationBuilder;
245    }
246
247    public DicomConfigurationBuilder optimisticLocking(boolean doOptimisticLocking) {
248        this.doOptimisticLocking = doOptimisticLocking;
249        return this;
250    }
251}