2 * Copyright 2011-2012 GRNET S.A. All rights reserved.
4 * Redistribution and use in source and binary forms, with or
5 * without modification, are permitted provided that the following
8 * 1. Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the following
12 * 2. Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials
15 * provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
24 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
30 * The views and conclusions contained in the software and
31 * documentation are those of the authors and should not be
32 * interpreted as representing official policies, either expressed
33 * or implied, of GRNET S.A.
36 package gr.grnet.aquarium
38 import com.ckkloverdos.convert.Converters
39 import com.ckkloverdos.maybe.Failed
40 import com.ckkloverdos.maybe.Just
41 import com.ckkloverdos.maybe.{Maybe, NoVal}
42 import com.ckkloverdos.props.Props
43 import com.ckkloverdos.resource.{FileStreamResource, StreamResource, CompositeStreamResourceContext, ClassLoaderStreamResourceContext, FileStreamResourceContext}
44 import com.ckkloverdos.sys.{SysEnv, SysProp}
45 import gr.grnet.aquarium.message.avro.AvroHelpers
46 import gr.grnet.aquarium.message.avro.gen.PolicyMsg
47 import gr.grnet.aquarium.util.justForSure
54 * @author Christos KK Loverdos <loverdos@gmail.com>
57 object ResourceLocator {
58 final object ResourceNames {
59 final val CONF_FODLER = "conf"
60 final val SLASH_ETC_AQUARIUM_FOLDER = "/etc/aquarium"
62 final val LOGBACK_XML = "logback.xml"
63 final val AQUARIUM_PROPERTIES = "aquarium.properties"
64 final val POLICY_JSON = "policy.json"
69 final val AKKA_HOME = "AKKA_HOME"
70 // final val AQUARIUM_HOME = "AQUARIUM_HOME"
73 final object Folders {
74 private[this] def checkFolder(name: String, file: File): File = {
75 if(!file.isDirectory) {
76 throw new AquariumInternalError(
77 "%s=%s is not a folder".format(
82 "%s [=%s]".format(file, file.getCanonicalFile)
90 * This is normally exported from the shell script (AQUARIUM_HOME) that starts Aquarium or given in the command
91 * line (aquarium.home).
93 * TODO: Make this searchable for resources (ie put it in the resource context)
95 final lazy val AquariumHome = {
96 SysProps.AquariumHome.value match {
97 case Just(aquariumHome) ⇒
98 checkFolder(SysProps.Names.AquariumHome, new File(aquariumHome))
101 throw new AquariumInternalError("Error regarding %s".format(SysProps.Names.AquariumHome), e)
104 SysEnvs.AQUARIUM_HOME.value match {
105 case Just(aquarium_home) ⇒
106 val folder = new File(aquarium_home)
107 checkFolder(SysEnvs.Names.AQUARIUM_HOME, folder)
108 SysProps.AquariumHome.update(folder.getPath) // needed for logback configuration
112 throw new AquariumInternalError("Error regarding %s".format(SysEnvs.Names.AQUARIUM_HOME), e)
115 val folder = new File(".")
116 SysProps.AquariumHome.update(folder.getPath) // needed for logback configuration
124 final object SysEnvs {
126 final val AKKA_HOME = Homes.Names.AKKA_HOME
127 final val AQUARIUM_HOME = "AQUARIUM_HOME"
130 final val AKKA_HOME = SysEnv(Names.AKKA_HOME)
131 final val AQUARIUM_HOME = SysEnv(Names.AQUARIUM_HOME)
134 final object SysProps {
136 final val AquariumHome = "aquarium.home"
137 final val AquariumPropertiesPath = "aquarium.properties.path"
138 final val AquariumConfFolder = "aquarium.conf.folder"
141 final val AquariumHome = SysProp(Names.AquariumHome)
144 * Use this property to override the place of aquarium.properties.
145 * If this is set, then it override any other way to specify the aquarium.properties location.
147 final val AquariumPropertiesPath = SysProp(Names.AquariumPropertiesPath)
150 * Use this property to override the place where aquarium configuration resides.
152 * The value of this property is a folder that defines the highest-priority resource context.
154 final val AquariumConfFolder = SysProp(Names.AquariumConfFolder)
157 final object ResourceContexts {
159 * AQUARIUM_HOME/conf resource context.
161 private[this] final lazy val HomeConfResourceContext = new FileStreamResourceContext(AQUARIUM_HOME_CONF_FOLDER)
164 * The venerable /etc resource context. Applicable in Unix environments
166 private[this] final lazy val SlashEtcResourceContext = new FileStreamResourceContext(ResourceNames.SLASH_ETC_AQUARIUM_FOLDER)
169 * Class loader resource context.
170 * This has the lowest priority.
172 private[this] final lazy val ClasspathBaseResourceContext = new ClassLoaderStreamResourceContext(
173 Thread.currentThread().getContextClassLoader)
175 private[this] final lazy val BasicResourceContext = new CompositeStreamResourceContext(
177 SlashEtcResourceContext,
178 HomeConfResourceContext,
179 ClasspathBaseResourceContext)
182 * The resource context used in the application.
184 final lazy val MasterResourceContext = {
185 SysProps.AquariumConfFolder.value match {
187 // We have a system override for the configuration location
188 new CompositeStreamResourceContext(
189 Just(BasicResourceContext),
190 new FileStreamResourceContext(value))
196 throw new AquariumInternalError(e)
201 final lazy val AQUARIUM_HOME_CONF_FOLDER = new File(Homes.Folders.AquariumHome, ResourceNames.CONF_FODLER)
204 * This exists in order to have a feeling of where we are.
206 final lazy val HERE = justForSure(getResource(".")).get.url.toExternalForm
208 final object Resources {
209 final lazy val AquariumPropertiesResource = {
210 ResourceLocator.SysProps.AquariumPropertiesPath.value match {
211 case Just(aquariumPropertiesPath) ⇒
212 // If we have a command-line override, prefer that
213 new FileStreamResource(new File(aquariumPropertiesPath))
217 throw new AquariumInternalError(
218 "Could not find %s".format(ResourceLocator.SysProps.Names.AquariumPropertiesPath), e)
221 // Otherwise try other locations
222 val aquariumPropertiesRCM = ResourceLocator getResource ResourceLocator.ResourceNames.AQUARIUM_PROPERTIES
223 aquariumPropertiesRCM match {
224 case Just(aquariumProperties) ⇒
229 throw new AquariumInternalError(
230 "Could not find %s".format(ResourceLocator.ResourceNames.AQUARIUM_PROPERTIES))
234 throw new AquariumInternalError(
235 "Could not find %s".format(ResourceLocator.ResourceNames.AQUARIUM_PROPERTIES), e)
240 final lazy val LogbackXMLResource = {
241 getResource(ResourceNames.LOGBACK_XML) match {
242 case Just(logbackXML) ⇒
246 throw new AquariumInternalError(
247 "Could not find %s".format(ResourceLocator.ResourceNames.LOGBACK_XML))
250 throw new AquariumInternalError(
251 "Could not find %s".format(ResourceLocator.ResourceNames.LOGBACK_XML), e)
256 final lazy val PolicyJSONResource = {
257 ResourceLocator.getResource(ResourceLocator.ResourceNames.POLICY_JSON) match {
258 case Just(policyJSON) ⇒
262 throw new AquariumInternalError(
263 "Could not find %s".format(ResourceLocator.ResourceNames.POLICY_JSON))
266 throw new AquariumInternalError(
267 "Could not find %s".format(ResourceLocator.ResourceNames.POLICY_JSON), e)
272 final lazy val AquariumProperties = {
273 implicit val DefaultConverters = Converters.DefaultConverters
274 val maybeProps = Props(Resources.AquariumPropertiesResource)
280 throw new AquariumInternalError(
281 "Could not load %s from %s".format(
282 ResourceLocator.ResourceNames.AQUARIUM_PROPERTIES,
283 Resources.AquariumPropertiesResource))
287 throw new AquariumInternalError(
288 "Could not load %s from %s".format(
289 ResourceLocator.ResourceNames.AQUARIUM_PROPERTIES,
290 Resources.AquariumPropertiesResource),
295 final lazy val DefaultPolicyMsg = {
296 val maybePolicyJSON = Resources.PolicyJSONResource.stringContent
297 maybePolicyJSON match {
299 throw new AquariumInternalError(
300 "Could not load %s from %s".format(
301 ResourceLocator.ResourceNames.POLICY_JSON,
302 Resources.PolicyJSONResource))
305 throw new AquariumInternalError(e,
306 "Could not load %s from %s".format(
307 ResourceLocator.ResourceNames.POLICY_JSON,
308 Resources.PolicyJSONResource))
310 case Just(jsonString) ⇒
311 try AvroHelpers.specificRecordOfJsonString(jsonString, new PolicyMsg)
314 throw error.asInstanceOf[Error]
317 throw new AquariumInternalError(t, "Cannot load default policy %s", Resources.PolicyJSONResource)
322 def getResource(what: String): Maybe[StreamResource] = {
323 ResourceContexts.MasterResourceContext.getResource(what)