
grails.util.Metadata.groovy Maven / Gradle / Ivy
/*
* Copyright 2004-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package grails.util
import grails.config.ConfigMap
import groovy.transform.CompileStatic
import org.grails.config.NavigableMap
import org.grails.io.support.FileSystemResource
import org.grails.io.support.Resource
import org.grails.io.support.UrlResource
import org.yaml.snakeyaml.Yaml
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.util.*;
/**
* Represents the application Metadata and loading mechanics.
*
* @author Graeme Rocher
* @since 1.1
*/
@CompileStatic
public class Metadata extends NavigableMap implements ConfigMap {
private static final long serialVersionUID = -582452926111226898L;
public static final String FILE = "application.yml";
public static final String APPLICATION_VERSION = "info.app.version";
public static final String APPLICATION_NAME = "info.app.name";
public static final String APPLICATION_GRAILS_VERSION = "info.app.grailsVersion";
public static final String SERVLET_VERSION = "info.app.servletVersion";
public static final String WAR_DEPLOYED = "info.app.warDeployed";
public static final String DEFAULT_SERVLET_VERSION = "3.0";
private static Holder> holder = new Holder>("Metadata");
public static final String BUILD_INFO_FILE = "META-INF/grails.build.info"
private Resource metadataFile;
private boolean warDeployed;
private String servletVersion = DEFAULT_SERVLET_VERSION;
private Object source;
private Metadata() {
loadFromDefault();
}
private Metadata(Resource res) {
loadFromFile(res);
}
private Metadata(File f) {
metadataFile = new FileSystemResource(f);
loadFromFile(metadataFile);
}
private Metadata(InputStream inputStream) {
loadFromInputStream(inputStream);
}
private Metadata(Map properties) {
merge(properties, true)
afterLoading();
}
/**
* @return The source of the metadata
*/
Object getSource() {
return source
}
public Resource getMetadataFile() {
return metadataFile;
}
/**
* Resets the current state of the Metadata so it is re-read.
*/
public static void reset() {
Metadata m = getFromMap();
if (m != null) {
m.clear();
m.afterLoading();
}
}
private void afterLoading() {
// allow override via system properties
merge(System.properties.findAll { key, val -> val }, true)
def value = get(WAR_DEPLOYED)
warDeployed = value != null ? Boolean.valueOf(value.toString()) : false
}
/**
* @return the metadata for the current application
*/
public static Metadata getCurrent() {
Metadata m = getFromMap();
if (m == null) {
m = new Metadata();
holder.set(new SoftReference(m));
}
return m;
}
private void loadFromDefault() {
try {
def classLoader = Thread.currentThread().getContextClassLoader()
URL url = classLoader.getResource(FILE);
if (url == null) {
url = getClass().getClassLoader().getResource(FILE);
}
if (url != null) {
url.withInputStream { input ->
this.@source = loadYml(input);
}
this.metadataFile = new UrlResource(url)
}
url = classLoader.getResource(BUILD_INFO_FILE);
if(url != null) {
url.withInputStream { input ->
loadAndMerge(input)
}
}
else {
// try WAR packaging resolve
url = classLoader.getResource("../../" + BUILD_INFO_FILE)
if(url != null) {
url.withInputStream { input ->
loadAndMerge(input)
}
}
}
afterLoading();
}
catch (Exception e) {
throw new RuntimeException("Cannot load application metadata:" + e.getMessage(), e);
}
}
private void loadAndMerge(InputStream input) {
try {
def props = new Properties()
props.load(input)
merge(props, true)
} catch (Throwable e) {
// ignore
}
}
private Object loadYml(InputStream input) {
Yaml yaml = new Yaml()
def loadedYaml = yaml.loadAll(input)
List result = []
for(Object yamlObject : loadedYaml) {
if(yamlObject instanceof Map) { // problem here with CompileStatic
result.add(yamlObject)
merge((Map)yamlObject)
}
}
return result
}
private void loadFromInputStream(InputStream inputStream) {
loadYml(inputStream);
afterLoading();
}
private void loadFromFile(Resource file) {
if (file != null && file.exists()) {
InputStream input = null;
try {
input = file.getInputStream();
loadYml(input);
afterLoading();
}
catch (Exception e) {
throw new RuntimeException("Cannot load application metadata:" + e.getMessage(), e);
}
finally {
closeQuietly(input);
}
}
}
/**
* Loads a Metadata instance from a Reader
* @param inputStream The InputStream
* @return a Metadata instance
*/
public static Metadata getInstance(InputStream inputStream) {
Metadata m = new Metadata(inputStream);
holder.set(new FinalReference(m));
return m;
}
/**
* Loads and returns a new Metadata object for the given File.
* @param file The File
* @return A Metadata object
*/
public static Metadata getInstance(File file) {
return getInstance(new FileSystemResource(file))
}
/**
* Loads and returns a new Metadata object for the given File.
* @param file The File
* @return A Metadata object
*/
public static Metadata getInstance(Resource file) {
Reference ref = holder.get();
if (ref != null) {
Metadata metadata = ref.get();
if (metadata != null && metadata.getMetadataFile() != null && metadata.getMetadataFile().equals(file)) {
return metadata;
}
else {
createAndBindNew(file);
}
}
return createAndBindNew(file);
}
private static Metadata createAndBindNew(Resource file) {
Metadata m = new Metadata(file);
holder.set(new FinalReference(m));
return m;
}
/**
* Reloads the application metadata.
* @return The metadata object
*/
public static Metadata reload() {
Resource f = getCurrent().getMetadataFile();
if (f != null && f.exists()) {
return getInstance(f);
}
return f == null ? new Metadata() : new Metadata(f);
}
/**
* @return The application version
*/
public String getApplicationVersion() {
return get(APPLICATION_VERSION)?.toString();
}
/**
* @return The Grails version used to build the application
*/
public String getGrailsVersion() {
return get(APPLICATION_GRAILS_VERSION)?.toString() ?: getClass().getPackage().getImplementationVersion();
}
/**
* @return The environment the application expects to run in
*/
public String getEnvironment() {
return get(Environment.KEY)?.toString();
}
/**
* @return The application name
*/
public String getApplicationName() {
return get(APPLICATION_NAME)?.toString();
}
/**
* @return The version of the servlet spec the application was created for
*/
public String getServletVersion() {
String servletVersion = get(SERVLET_VERSION)?.toString();
if (servletVersion == null) {
servletVersion = System.getProperty(SERVLET_VERSION) != null ? System.getProperty(SERVLET_VERSION) : this.servletVersion;
return servletVersion;
}
return servletVersion;
}
public void setServletVersion(String servletVersion) {
this.servletVersion = servletVersion;
}
/**
* @return true if this application is deployed as a WAR
*/
public boolean isWarDeployed() {
Environment.isWarDeployed()
}
/**
* @return True if the development sources are present
*/
boolean isDevelopmentEnvironmentAvailable() {
return Environment.isDevelopmentEnvironmentAvailable()
}
private static void closeQuietly(Closeable c) {
if (c != null) {
try {
c.close();
}
catch (Exception ignored) {
// ignored
}
}
}
private static Metadata getFromMap() {
Reference metadata = holder.get();
return metadata == null ? null : metadata.get();
}
static class FinalReference extends SoftReference {
private final T ref;
public FinalReference(T t) {
super(t);
ref = t;
}
@Override
public T get() {
return ref;
}
}
@Override
def T getProperty(String key, Class targetType) {
return get(key)?.asType(targetType)
}
@Override
def T getProperty(String key, Class targetType, T defaultValue) {
def v = getProperty(key, targetType)
if(v == null) {
return defaultValue
}
return v
}
@Override
def T getRequiredProperty(String key, Class targetType) throws IllegalStateException {
def value = get(key)
if(value == null) {
throw new IllegalStateException("Value for key ["+key+"] cannot be resolved");
}
return value.asType(targetType)
}
@Override
Iterator> iterator() {
return entrySet().iterator()
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy