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