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.maybe.{Maybe, NoVal}
39 import com.ckkloverdos.sys.{SysEnv, SysProp}
42 import gr.grnet.aquarium.util.justForSure
43 import com.ckkloverdos.resource.{FileStreamResource, StreamResource, CompositeStreamResourceContext, ClassLoaderStreamResourceContext, FileStreamResourceContext}
44 import com.ckkloverdos.props.Props
45 import com.ckkloverdos.maybe.Just
46 import com.ckkloverdos.maybe.Failed
47 import com.ckkloverdos.convert.Converters
48 import gr.grnet.aquarium.converter.{JsonTextFormat, StdConverters}
49 import gr.grnet.aquarium.policy.StdPolicy
50 import gr.grnet.aquarium.message.avro.AvroHelpers
51 import gr.grnet.aquarium.message.avro.gen.PolicyMsg
56 * @author Christos KK Loverdos <loverdos@gmail.com>
59 object ResourceLocator {
60 final object ResourceNames {
61 final val CONF_FODLER = "conf"
62 final val SLASH_ETC_AQUARIUM_FOLDER = "/etc/aquarium"
64 final val LOGBACK_XML = "logback.xml"
65 final val AQUARIUM_PROPERTIES = "aquarium.properties"
66 final val POLICY_JSON = "policy.json"
71 final val AKKA_HOME = "AKKA_HOME"
72 // final val AQUARIUM_HOME = "AQUARIUM_HOME"
75 final object Folders {
76 private[this] def checkFolder(name: String, file: File): File = {
77 if(!file.isDirectory) {
78 throw new AquariumInternalError(
79 "%s=%s is not a folder".format(
84 "%s [=%s]".format(file, file.getCanonicalFile)
92 * This is normally exported from the shell script (AQUARIUM_HOME) that starts Aquarium or given in the command
93 * line (aquarium.home).
95 * TODO: Make this searchable for resources (ie put it in the resource context)
97 final lazy val AquariumHome = {
98 SysProps.AquariumHome.value match {
99 case Just(aquariumHome) ⇒
100 checkFolder(SysProps.Names.AquariumHome, new File(aquariumHome))
103 throw new AquariumInternalError("Error regarding %s".format(SysProps.Names.AquariumHome), e)
106 SysEnvs.AQUARIUM_HOME.value match {
107 case Just(aquarium_home) ⇒
108 val folder = new File(aquarium_home)
109 checkFolder(SysEnvs.Names.AQUARIUM_HOME, folder)
110 SysProps.AquariumHome.update(folder.getPath) // needed for logback configuration
114 throw new AquariumInternalError("Error regarding %s".format(SysEnvs.Names.AQUARIUM_HOME), e)
117 val folder = new File(".")
118 SysProps.AquariumHome.update(folder.getPath) // needed for logback configuration
126 final object SysEnvs {
128 final val AKKA_HOME = Homes.Names.AKKA_HOME
129 final val AQUARIUM_HOME = "AQUARIUM_HOME"
132 final val AKKA_HOME = SysEnv(Names.AKKA_HOME)
133 final val AQUARIUM_HOME = SysEnv(Names.AQUARIUM_HOME)
136 final object SysProps {
138 final val AquariumHome = "aquarium.home"
139 final val AquariumPropertiesPath = "aquarium.properties.path"
140 final val AquariumConfFolder = "aquarium.conf.folder"
143 final val AquariumHome = SysProp(Names.AquariumHome)
146 * Use this property to override the place of aquarium.properties.
147 * If this is set, then it override any other way to specify the aquarium.properties location.
149 final val AquariumPropertiesPath = SysProp(Names.AquariumPropertiesPath)
152 * Use this property to override the place where aquarium configuration resides.
154 * The value of this property is a folder that defines the highest-priority resource context.
156 final val AquariumConfFolder = SysProp(Names.AquariumConfFolder)
159 final object ResourceContexts {
161 * AQUARIUM_HOME/conf resource context.
163 private[this] final lazy val HomeConfResourceContext = new FileStreamResourceContext(AQUARIUM_HOME_CONF_FOLDER)
166 * The venerable /etc resource context. Applicable in Unix environments
168 private[this] final lazy val SlashEtcResourceContext = new FileStreamResourceContext(ResourceNames.SLASH_ETC_AQUARIUM_FOLDER)
171 * Class loader resource context.
172 * This has the lowest priority.
174 private[this] final lazy val ClasspathBaseResourceContext = new ClassLoaderStreamResourceContext(
175 Thread.currentThread().getContextClassLoader)
177 private[this] final lazy val BasicResourceContext = new CompositeStreamResourceContext(
179 SlashEtcResourceContext,
180 HomeConfResourceContext,
181 ClasspathBaseResourceContext)
184 * The resource context used in the application.
186 final lazy val MasterResourceContext = {
187 SysProps.AquariumConfFolder.value match {
189 // We have a system override for the configuration location
190 new CompositeStreamResourceContext(
191 Just(BasicResourceContext),
192 new FileStreamResourceContext(value))
198 throw new AquariumInternalError(e)
203 final lazy val AQUARIUM_HOME_CONF_FOLDER = new File(Homes.Folders.AquariumHome, ResourceNames.CONF_FODLER)
206 * This exists in order to have a feeling of where we are.
208 final lazy val HERE = justForSure(getResource(".")).get.url.toExternalForm
210 final object Resources {
211 final lazy val AquariumPropertiesResource = {
212 ResourceLocator.SysProps.AquariumPropertiesPath.value match {
213 case Just(aquariumPropertiesPath) ⇒
214 // If we have a command-line override, prefer that
215 new FileStreamResource(new File(aquariumPropertiesPath))
219 throw new AquariumInternalError(
220 "Could not find %s".format(ResourceLocator.SysProps.Names.AquariumPropertiesPath), e)
223 // Otherwise try other locations
224 val aquariumPropertiesRCM = ResourceLocator getResource ResourceLocator.ResourceNames.AQUARIUM_PROPERTIES
225 aquariumPropertiesRCM match {
226 case Just(aquariumProperties) ⇒
231 throw new AquariumInternalError(
232 "Could not find %s".format(ResourceLocator.ResourceNames.AQUARIUM_PROPERTIES))
236 throw new AquariumInternalError(
237 "Could not find %s".format(ResourceLocator.ResourceNames.AQUARIUM_PROPERTIES), e)
242 final lazy val LogbackXMLResource = {
243 getResource(ResourceNames.LOGBACK_XML) match {
244 case Just(logbackXML) ⇒
248 throw new AquariumInternalError(
249 "Could not find %s".format(ResourceLocator.ResourceNames.LOGBACK_XML))
252 throw new AquariumInternalError(
253 "Could not find %s".format(ResourceLocator.ResourceNames.LOGBACK_XML), e)
258 final lazy val PolicyJSONResource = {
259 ResourceLocator.getResource(ResourceLocator.ResourceNames.POLICY_JSON) match {
260 case Just(policyJSON) ⇒
264 throw new AquariumInternalError(
265 "Could not find %s".format(ResourceLocator.ResourceNames.POLICY_JSON))
268 throw new AquariumInternalError(
269 "Could not find %s".format(ResourceLocator.ResourceNames.POLICY_JSON), e)
274 final lazy val AquariumProperties = {
275 implicit val DefaultConverters = Converters.DefaultConverters
276 val maybeProps = Props(Resources.AquariumPropertiesResource)
282 throw new AquariumInternalError(
283 "Could not load %s from %s".format(
284 ResourceLocator.ResourceNames.AQUARIUM_PROPERTIES,
285 Resources.AquariumPropertiesResource))
289 throw new AquariumInternalError(
290 "Could not load %s from %s".format(
291 ResourceLocator.ResourceNames.AQUARIUM_PROPERTIES,
292 Resources.AquariumPropertiesResource),
297 final lazy val DefaultPolicyMsg = {
298 val maybePolicyJSON = Resources.PolicyJSONResource.stringContent
299 maybePolicyJSON match {
301 throw new AquariumInternalError(
302 "Could not load %s from %s".format(
303 ResourceLocator.ResourceNames.POLICY_JSON,
304 Resources.PolicyJSONResource))
307 throw new AquariumInternalError(e,
308 "Could not load %s from %s".format(
309 ResourceLocator.ResourceNames.POLICY_JSON,
310 Resources.PolicyJSONResource))
312 case Just(jsonString) ⇒
313 try AvroHelpers.specificRecordOfJsonString(jsonString, new PolicyMsg)
316 throw error.asInstanceOf[Error]
319 throw new AquariumInternalError(t, "Cannot load default policy %s", Resources.PolicyJSONResource)
325 def getResource(what: String): Maybe[StreamResource] = {
326 ResourceContexts.MasterResourceContext.getResource(what)