Merge "Inherit from oparent"
[vfc/nfvo/wfengine.git] / winery / org.eclipse.winery.repository / src / main / java / org / eclipse / winery / repository / Prefs.java
1 /*******************************************************************************
2  * Copyright (c) 2012-2014 University of Stuttgart.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * and the Apache License 2.0 which both accompany this distribution,
6  * and are available at http://www.eclipse.org/legal/epl-v10.html
7  * and http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Contributors:
10  *     Oliver Kopp - initial API and implementation
11  *     C. Timurhan Sungur - jClouds preferences
12  *******************************************************************************/
13 package org.eclipse.winery.repository;
14
15 import java.io.File;
16 import java.io.FileInputStream;
17 import java.io.FileNotFoundException;
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.security.AccessControlException;
21 import java.util.Locale;
22 import java.util.Properties;
23
24 import javax.servlet.ServletContext;
25 import javax.servlet.ServletContextEvent;
26 import javax.servlet.ServletContextListener;
27
28 import org.eclipse.winery.common.TOSCADocumentBuilderFactory;
29 import org.eclipse.winery.repository.backend.IRepository;
30 import org.eclipse.winery.repository.backend.filebased.FilebasedRepository;
31 import org.eclipse.winery.repository.backend.filebased.GitBasedRepository;
32 import org.eclipse.winery.repository.runtimeintegration.OpenTOSCAContainerConnection;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 public class Prefs implements ServletContextListener {
37         
38         // set by the constructors
39         // We have to do this hack as the servlet container initializes this class
40         // on its own and we want to have a *single* instance of this class.
41         public static Prefs INSTANCE;
42         
43         private static final Logger logger = LoggerFactory.getLogger(Prefs.class);
44         
45         protected IRepository repository = null;
46         
47         private ServletContext context;
48         
49         private Boolean isContainerLocallyAvailable = null;
50         
51         private Boolean isRestDocDocumentationAvailable = null;
52         
53         private Boolean isPlanBuilderAvailable = null;
54         
55         // location of the winery topology modeler
56         private String wineryTopologyModelerPath = null;
57         
58         // the properties from winery.properties
59         protected Properties properties = null;
60         
61         // package visibility to ease testing
62         static final String PROP_JCLOUDS_CONTEXT_PROVIDER = "jclouds.context.provider";
63         static final String PROP_JCLOUDS_CONTEXT_IDENTITY = "jclouds.context.identity";
64         static final String PROP_JCLOUDS_CONTEXT_CREDENTIAL = "jclouds.context.credential";
65         static final String PROP_JCLOUDS_BLOBSTORE_LOCATION = "jclouds.blobstore.location";
66         static final String PROP_JCLOUDS_CONTAINERNAME = "jclouds.blobstore.container";
67         static final String PROP_JCLOUDS_END_POINT = "jclouds.blobstore.endpoint";
68         
69         static final String PROP_BPMN4TOSCA_MODELER_URI = "bpmn4toscamodelerBaseURI";
70         
71         
72         /**
73          * This constructor is called at handling at servlets, too. Therefore, we
74          * make it private. If testing is needed, an additional paramater has to be
75          * passed
76          */
77         public Prefs() {
78                 Prefs.INSTANCE = this;
79         }
80         
81         /**
82          * Constructor for Unit testing ONLY!
83          * 
84          * @param initializeRepository true if the repository should be initialized
85          *            as provided in winery.properties
86          * @throws IOException
87          * @warning Do not call! (except from Unit testing code)
88          */
89         protected Prefs(boolean initializeRepository) throws IOException {
90                 this();
91                 
92                 // emulate behavior of doInitialization(Context)
93                 Properties p = new Properties();
94                 InputStream is = this.getClass().getClassLoader().getResourceAsStream("winery.properties");
95                 if (is != null) {
96                         p.load(is);
97                 }
98                 this.properties = p;
99                 
100                 if (initializeRepository) {
101                         this.doRepositoryInitialization();
102                 }
103         }
104         
105         /**
106          * Initialization code for the repository. Should go into separate class,
107          * but being here should be OK for a prototype
108          * 
109          * Called from both the constructor for JUnit and the servlet-based
110          * initialization
111          * 
112          * Pre-Condition: this.properties is set.
113          */
114         private void doRepositoryInitialization() {
115                 assert (this.properties != null);
116                 
117                 String provider = this.properties.getProperty(Prefs.PROP_JCLOUDS_CONTEXT_PROVIDER);
118                 if (provider != null) {
119                         // repository runs via jclouds
120                         // String identity = this.properties.getProperty(Prefs.PROP_JCLOUDS_CONTEXT_IDENTITY);
121                         // String credential = this.properties.getProperty(Prefs.PROP_JCLOUDS_CONTEXT_CREDENTIAL);
122                         // String location = this.properties.getProperty(Prefs.PROP_JCLOUDS_BLOBSTORE_LOCATION);
123                         // String containerName = this.properties.getProperty(Prefs.PROP_JCLOUDS_CONTAINERNAME);
124                         // String endPoint = this.properties.getProperty(Prefs.PROP_JCLOUDS_END_POINT);
125                         Prefs.logger.error("jClouds is currently not supported due to jClouds not yet approved by Eclipse. Falling back to local storages");
126                         provider = null;
127                         // Prefs.logger.info("Using jclouds as interface to the repository");
128                         // this.repository = new JCloudsBasedRepository(provider, identity, credential, location, containerName, endPoint);
129                 } // else {
130                 if (provider == null) {
131                         String repositoryLocation = this.properties.getProperty("repositoryPath");
132                         Prefs.logger.debug("Repository location: {}", repositoryLocation);
133                         Prefs.logger.debug("Trying git-based backend");
134                         try {
135                                 this.repository = new GitBasedRepository(repositoryLocation);
136                                 Prefs.logger.debug("git-based backend is used");
137                         } catch (Throwable e) {
138                                 Prefs.logger.trace(e.getMessage());
139                                 Prefs.logger.debug("There seems to be no git repository at the specified location. We fall back to the file-based repository");
140                                 this.repository = new FilebasedRepository(repositoryLocation);
141                         }
142                 }
143         }
144         
145         private void doInitialization(ServletContext ctx) {
146                 if (Locale.getDefault() != Locale.ENGLISH) {
147                         try {
148                                 // needed for {@link
149                                 // org.eclipse.winery.repository.filesystem.Utils.returnFile(File,
150                                 // String)}
151                                 Locale.setDefault(Locale.ENGLISH);
152                         } catch (AccessControlException e) {
153                                 // Happens at Google App Engine
154                                 Prefs.logger.error("Could not switch locale to English", e);
155                         }
156                 }
157                 
158                 this.context = ctx;
159                 
160                 // Reading //
161                 final String fn = "/WEB-INF/classes/winery.properties";
162                 Prefs.logger.debug("Trying to read ".concat(ctx.getRealPath(fn)));
163                 InputStream inStream = ctx.getResourceAsStream(fn);
164                 // alternative: InputStream inStream = this.getClass().getClassLoader().getResourceAsStream("winery.properties");
165                 Properties p = new Properties();
166                 if (inStream == null) {
167                         Prefs.logger.info(fn + " does not exist.");
168                         
169                         // We search for winery.properties on the filesystem in the repository
170                         
171                         File propFile = new File(FilebasedRepository.getDefaultRepositoryFilePath(), "winery.properties");
172                         Prefs.logger.info("Trying " + propFile.getAbsolutePath());
173                         if (propFile.exists()) {
174                                 Prefs.logger.info("Found");
175                                 // if winery.property exists in the root of the default repository path (~/winery-repository), load it
176                                 try (InputStream is2 = new FileInputStream(propFile)) {
177                                         p.load(is2);
178                                 } catch (IOException e) {
179                                         Prefs.logger.error("Could not load winery.properties", e);
180                                 }
181                         } else {
182                                 Prefs.logger.info("Not found");
183                         }
184                 } else {
185                         try {
186                                 p.load(inStream);
187                                 try {
188                                         inStream.close();
189                                 } catch (IOException e) {
190                                         Prefs.logger.error("Could not close stream of winery.properties", e);
191                                 }
192                         } catch (FileNotFoundException e) {
193                                 // OK if file does not exist
194                         } catch (IOException e) {
195                                 Prefs.logger.error("Could not load winery.properties", e);
196                         }
197                 }
198                 
199                 this.wineryTopologyModelerPath = p.getProperty("topologymodeler");
200                 
201                 // make the properties known in the class
202                 this.properties = p;
203                 
204                 this.doRepositoryInitialization();
205                 
206                 // Initialize XSD validation in the background. Takes up a few seconds.
207                 // If we do not do it here, the first save by a user takes a few seconds, which is inconvenient
208                 new Thread() {
209                         
210                         @Override
211                         public void run() {
212                                 Prefs.logger.debug("Initializing XML validation");
213                                 @SuppressWarnings("unused")
214                                 TOSCADocumentBuilderFactory tdbf = TOSCADocumentBuilderFactory.INSTANCE;
215                                 Prefs.logger.debug("Initialized XML validation");
216                         }
217                 }.start();
218         }
219         
220         public IRepository getRepository() {
221                 return this.repository;
222         }
223         
224         @Override
225         public void contextInitialized(ServletContextEvent arg0) {
226                 Prefs.INSTANCE.doInitialization(arg0.getServletContext());
227         }
228         
229         @Override
230         public void contextDestroyed(ServletContextEvent arg0) {
231                 // nothing to do at tear down
232         }
233         
234         /**
235          * @return the path of the root resource
236          */
237         public String getResourcePath() {
238                 return this.context.getContextPath();
239         }
240         
241         /**
242          * @return the path to the winery topology modeler. Without trailing slash
243          */
244         public String getWineryTopologyModelerPath() {
245                 if (this.wineryTopologyModelerPath == null) {
246                         // derive the path from the current path
247                         String res = this.getResourcePath();
248                         if (res.endsWith("/")) {
249                                 res = res.substring(0, res.length() - 1);
250                         }
251                         int pos = res.lastIndexOf("/");
252                         if (pos <= 0) {
253                                 res = "/winery-topologymodeler";
254                         } else {
255                                 res = res.substring(0, pos);
256                                 res = res + "winery-topologymodeler";
257                         }
258                         return res;
259                 } else {
260                         assert (this.wineryTopologyModelerPath != null);
261                         return this.wineryTopologyModelerPath;
262                 }
263         }
264         
265         /**
266          * Returns the read content from winery.properties.
267          * 
268          * @return the internal object held by this class. Manipulations on this
269          *         object may cause trouble.
270          */
271         public Properties getProperties() {
272                 return this.properties;
273         }
274         
275         /**
276          * @return the version of winery
277          */
278         public String getVersion() {
279                 return Version.VERSION;
280         }
281         
282         /**
283          * @return true if the OpenTOSCA container is locally available
284          */
285         public boolean isContainerLocallyAvailable() {
286                 if (this.isContainerLocallyAvailable == null) {
287                         // we initialize the variable at the first read
288                         // The container and Winery are started simultaneously
289                         // Therefore, the container might not be available if Winery is starting
290                         // When checking at the first read, chances are high that the container started
291                         this.isContainerLocallyAvailable = OpenTOSCAContainerConnection.isContainerLocallyAvailable();
292                 }
293                 return this.isContainerLocallyAvailable;
294         }
295         
296         /**
297          * @return true if the plan generator is available
298          */
299         public boolean isPlanBuilderAvailable() {
300                 // similar implementation as isContainerLocallyAvailable()
301                 if (this.isPlanBuilderAvailable == null) {
302                         String planBuilderURI = "http://localhost:1339/planbuilder";
303                         this.isPlanBuilderAvailable = Utils.isResourceAvailable(planBuilderURI);
304                 }
305                 return this.isPlanBuilderAvailable;
306         }
307         
308         /**
309          * Quick hack to check whether a RestDoc documentation is available at
310          * /restdoc.html. We do not deliver
311          */
312         public boolean isRestDocDocumentationAvailable() {
313                 String path = "http://localhost:8080/restdoc.html";
314                 if (this.isRestDocDocumentationAvailable == null) {
315                         // we initialize the variable at the first read
316                         // The container and Winery are started simultaneously
317                         // Therefore, the container might not be available if Winery is starting
318                         // When checking at the first read, chances are high that the container started
319                         this.isRestDocDocumentationAvailable = Utils.isResourceAvailable(path);
320                 }
321                 return this.isRestDocDocumentationAvailable;
322         }
323         
324         /**
325          * @return the base URL of the BPMN4TOSCA plan modeler. NULL if not
326          *         configured. May also be empty.
327          */
328         public String getBPMN4TOSCABaseURL() {
329                 return this.properties.getProperty(Prefs.PROP_BPMN4TOSCA_MODELER_URI);
330         }
331         
332 }