001/*
002 *                    PDB web development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 *
015 * Created on Jul 8, 2009
016 * Created by ap3
017 *
018 */
019
020package org.biojava.nbio.structure.align.util;
021
022import org.biojava.nbio.structure.align.ce.StartupParameters;
023import org.biojava.nbio.structure.io.LocalPDBDirectory.FetchBehavior;
024import org.biojava.nbio.structure.io.LocalPDBDirectory.ObsoleteBehavior;
025import org.biojava.nbio.core.util.PrettyXMLWriter;
026import org.biojava.nbio.core.util.XMLWriter;
027import org.biojava.nbio.structure.io.StructureFiletype;
028import org.slf4j.Logger;
029import org.slf4j.LoggerFactory;
030
031import java.io.File;
032import java.io.IOException;
033import java.io.PrintWriter;
034import java.util.Map;
035import java.util.concurrent.atomic.AtomicBoolean;
036
037
038/** A container to persist config to the file system
039 *
040 * @author Andreas Prlic
041 *
042 */
043public class UserConfiguration
044{
045
046        private static final Logger logger = LoggerFactory.getLogger(UserConfiguration.class);
047
048        public static final String PDB_FORMAT   = "PDB";
049        public static final String MMCIF_FORMAT = "mmCif";
050        public static final String MMTF_FORMAT  = "mmtf";
051        public static final String BCIF_FORMAT  = "bcif";
052
053        public static final String TMP_DIR = "java.io.tmpdir";
054
055        public static final String PDB_DIR   = "PDB_DIR";
056        public static final String PDB_CACHE_DIR = "PDB_CACHE_DIR";
057
058        public static final String lineSplit = System.getProperty("file.separator");
059
060        private String pdbFilePath;
061        private String cacheFilePath;
062
063        private FetchBehavior fetchBehavior;
064        private ObsoleteBehavior obsoleteBehavior;
065
066        private String fileFormat;
067
068        private static AtomicBoolean warningShown = new AtomicBoolean(false);
069
070
071        /**
072         * Default UserConfiguration:
073         * <ul>
074         * <li>split directory</li>
075         * <li>autofetch files</li>
076         * <li>default download location. This is the first specified of:
077         *      <ol><li>{@value #PDB_DIR} system property (for instance, -D{@value #PDB_DIR}=/tmp)</li>
078         *   <li>{@value #PDB_DIR} environment variable</li>
079         *   <li>System temp directory (java.io.tmpdir property)</li>
080         *   </ol>
081         *   if the provided path is not a directory then
082         *   the system's temp directory is used. A non-writable path is allowed,
083         *   only a warning will be logged.
084         * </li>
085         * <li>default cache location. This is the first specified of:
086         *      <ol><li>{@value #PDB_CACHE_DIR} system property (for instance, -D{@value #PDB_CACHE_DIR}=/tmp)</li>
087         *   <li>{@value #PDB_CACHE_DIR} environment variable</li>
088         *   <li>the value set for {@value #PDB_DIR}</li>
089         *   </ol>
090         *   if the provided path is not a directory or is not writable then
091         *   the system's temp directory is used.
092         * </li>
093         * </ul>
094         */
095        public UserConfiguration(){
096                fetchBehavior = FetchBehavior.DEFAULT;
097                obsoleteBehavior = ObsoleteBehavior.DEFAULT;
098
099                pdbFilePath = initPdbFilePath();
100                // note that in initCacheFilePath, we set to the provided one (if readable) or to the same as pdbFilePath
101                cacheFilePath = initCacheFilePath();
102
103                fileFormat = BCIF_FORMAT;
104        }
105
106        private String initPdbFilePath() {
107
108                String path = null;
109
110                String propertyName = PDB_DIR;
111
112                String userProvidedDir = System.getProperty(propertyName);
113
114                if ( userProvidedDir != null && !userProvidedDir.trim().isEmpty()) {
115
116                        path = userProvidedDir;
117                        logger.debug("Read PDB dir from system property {}: {}", propertyName, path);
118                        File f = new File(path);
119                        if (!f.isDirectory()) {
120                                logger.warn(
121                                                "Provided path {} (with system property {}) is not a directory. Using system's temp directory instead {}",
122                                                path, propertyName, System.getProperty(TMP_DIR));
123                                path = System.getProperty(TMP_DIR);
124                        } else if (!f.canWrite()) {
125                                logger.warn(
126                                                "Provided path {} (with system property {}) is not writable. Will not be able to write cached files.",
127                                                path, propertyName);
128                                // we don't require the PDB_DIR to be writable, so that it can be used with a pre-rsynced dir
129                                // thus if not writable, we only warn and go ahead using it
130                        }
131
132
133                } else {
134                        Map<String,String> env = System.getenv();
135
136                        if( env.containsKey(propertyName) && !env.get(propertyName).trim().isEmpty()) {
137                                path = env.get(propertyName);
138                                logger.debug("Read dir from environment variable {}: {}", propertyName, path);
139
140                                File f = new File(path);
141                                if (!f.isDirectory()) {
142                                        logger.warn(
143                                                        "Provided path {} (with environment variable {}) is not a directory. Using system's temp directory instead {}",
144                                                        path, propertyName, System.getProperty(TMP_DIR));
145                                        path = System.getProperty(TMP_DIR);
146                                } else if (!f.canWrite()) {
147                                        logger.warn(
148                                                        "Provided path {} (with environment variable {}) is not writable. Will not be able to write cached files",
149                                                        path, propertyName);
150                                        // we don't require the PDB_DIR to be writable, so that it can be used with a pre-rsynced dir
151                                        // thus if not writable, we only warn and go ahead using it
152                                }
153
154                        } else {
155                                path = System.getProperty(TMP_DIR);
156
157                                if ( ! warningShown.get()) {
158
159                                        logger.warn("Could not read dir from system property {} or environment variable {}, "
160                                                                        + "using system's temp directory {}",
161                                                        propertyName, propertyName, path);
162
163                                        warningShown.set(true);
164                                }
165
166                                System.setProperty(propertyName,path);
167                        }
168                }
169
170                if ( ! path.endsWith(lineSplit) )
171                        path = path + lineSplit;
172
173                return path;
174
175        }
176
177        private String initCacheFilePath() {
178
179                String path = null;
180
181                String propertyName = PDB_CACHE_DIR;
182
183                String userProvidedDir = System.getProperty(propertyName);
184
185                if ( userProvidedDir != null ) {
186
187                        path = userProvidedDir;
188                        logger.debug("Read cache dir from system property {}: {}", propertyName, path);
189                        File f = new File(path);
190                        if (!f.isDirectory()) {
191                                logger.warn(
192                                                "Provided path {} (with system property {}) is not a directory. Using system's temp directory instead {}",
193                                                path, propertyName, System.getProperty(TMP_DIR));
194                                path = System.getProperty(TMP_DIR);
195                        } else if (!f.canWrite()) {
196                                logger.warn(
197                                                "Provided path {} (with system property {}) is not writable. Using system's temp directory instead {}",
198                                                path, propertyName, System.getProperty(TMP_DIR));
199                                path = System.getProperty(TMP_DIR);
200                                System.setProperty(propertyName,path);
201                        }
202
203
204                } else {
205                        Map<String,String> env = System.getenv();
206
207                        if( env.containsKey(propertyName)) {
208                                path = env.get(propertyName);
209                                logger.debug("Read dir from environment variable {}: {}", propertyName, path);
210
211                                File f = new File(path);
212                                if (!f.isDirectory()) {
213                                        logger.warn(
214                                                        "Provided path {} (with environment variable {}) is not a directory. Using system's temp directory instead {}",
215                                                        path, propertyName, System.getProperty(TMP_DIR));
216                                        path = System.getProperty(TMP_DIR);
217                                } else if (!f.canWrite()) {
218                                        logger.warn(
219                                                        "Provided path {} (with environment variable {}) is not writable. Using system's temp directory instead {}",
220                                                        path, propertyName, System.getProperty(TMP_DIR));
221                                        path = System.getProperty(TMP_DIR);
222                                }
223
224                        } else {
225                                // NOTE in case of not provided, then it is set to same as pdbFilePath
226                                // as PDB_DIR is not checked for being writable, we have to do that check here in case
227                                if (new File(pdbFilePath).canWrite()){
228                                        path = pdbFilePath;
229                                        logger.info("Could not read cache dir from system property {} or environment variable {}, "
230                                                        + "using PDB directory instead {}",
231                                                        propertyName, propertyName, path);
232                                        System.setProperty(propertyName,path);
233
234                                } else {
235                                        path = System.getProperty(TMP_DIR);
236                                        logger.warn("Could not read cache dir from system property {} or environment variable {}, "
237                                                        + "and PDB directory {} is not writable. Using system's temp directory instead {}",
238                                                        propertyName, propertyName, pdbFilePath, path);
239                                        System.setProperty(propertyName,path);
240
241                                }
242                        }
243                }
244
245                if ( ! path.endsWith(lineSplit) )
246                        path = path + lineSplit;
247
248                return path;
249
250        }
251
252        public String getPdbFilePath()
253        {
254                return pdbFilePath;
255        }
256
257        public void setPdbFilePath(String pdbFilePath)
258        {
259                this.pdbFilePath = pdbFilePath;
260        }
261
262        public String getCacheFilePath() {
263                return cacheFilePath;
264        }
265
266        public void setCacheFilePath(String cacheFilePath) {
267                this.cacheFilePath = cacheFilePath;
268        }
269
270        public FetchBehavior getFetchBehavior() {
271                return fetchBehavior;
272        }
273
274        public void setFetchBehavior(FetchBehavior fetchBehavior) {
275                this.fetchBehavior = fetchBehavior;
276        }
277
278        public ObsoleteBehavior getObsoleteBehavior() {
279                return obsoleteBehavior;
280        }
281
282        public void setObsoleteBehavior(ObsoleteBehavior obsoleteBehavior) {
283                this.obsoleteBehavior = obsoleteBehavior;
284        }
285
286        /** convert Configuration to an XML file so it can be serialized
287         *
288         * @param pw
289         * @return XMLWriter
290         * @throws IOException
291         */
292        public XMLWriter toXML(PrintWriter pw)
293                        throws IOException
294                        {
295
296                XMLWriter     xw = new PrettyXMLWriter( pw);
297
298                toXML(xw);
299                return xw ;
300                        }
301
302
303        /** convert Configuration to an XML file so it can be serialized
304         * add to an already existing xml file.
305         *
306         * @param xw the XML writer to use
307         * @return the writer again
308         * @throws IOException
309         * @see org.biojava.nbio.structure.align.webstart.ConfigXMLHandler
310         */
311
312        public XMLWriter toXML(XMLWriter xw)
313                        throws IOException
314                        {
315                xw.printRaw("<?xml version='1.0' standalone='no' ?>");
316                //xw.printRaw("<!DOCTYPE " + XML_CONTENT_TYPE + " SYSTEM '" + XML_DTD + "' >");
317                xw.openTag("JFatCatConfig");
318
319                xw.openTag("PDBFILEPATH");
320                // we don;t serialize the tempdir...
321                String tempdir = System.getProperty(TMP_DIR);
322                if (! pdbFilePath.equals(tempdir))
323                        xw.attribute("path", pdbFilePath);
324
325                xw.attribute("fetchBehavior", fetchBehavior+"");
326                xw.attribute("obsoleteBehavior", obsoleteBehavior+"");
327                xw.attribute("fileFormat", fileFormat);
328                xw.closeTag("PDBFILEPATH");
329
330                xw.closeTag("JFatCatConfig");
331                return xw ;
332
333                        }
334
335        public static UserConfiguration fromStartupParams(StartupParameters params) {
336                UserConfiguration config = new UserConfiguration();
337                config.setPdbFilePath(params.getPdbFilePath());
338
339                if(params.isAutoFetch()) {
340                        config.setFetchBehavior(FetchBehavior.DEFAULT);
341                } else {
342                        config.setFetchBehavior(FetchBehavior.LOCAL_ONLY);
343                }
344
345                // TODO support MMCif Files
346                config.setFileFormat(UserConfiguration.PDB_FORMAT);
347                return config;
348        }
349
350        public void setFileFormat (String fileFormat){
351                this.fileFormat = fileFormat;
352        }
353
354        public String getFileFormat()
355        {
356                return fileFormat;
357        }
358
359        public StructureFiletype getStructureFiletype() {
360                switch (fileFormat) {
361                        case MMCIF_FORMAT:
362                                return StructureFiletype.CIF;
363                        case PDB_FORMAT:
364                                return StructureFiletype.PDB;
365                        case MMTF_FORMAT:
366                                return StructureFiletype.MMTF;
367                        case BCIF_FORMAT:
368                        default:
369                                return StructureFiletype.BCIF;
370                }
371        }
372}