001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019 020package org.apache.isis.core.commons.config; 021 022import java.io.IOException; 023import java.util.ArrayList; 024import java.util.List; 025import java.util.Set; 026 027import com.google.common.base.Objects; 028import com.google.common.collect.Sets; 029 030import org.slf4j.Logger; 031import org.slf4j.LoggerFactory; 032 033import org.apache.isis.core.commons.exceptions.IsisException; 034import org.apache.isis.core.commons.resource.ResourceStreamSource; 035import org.apache.isis.core.commons.resource.ResourceStreamSourceChainOfResponsibility; 036import org.apache.isis.core.commons.resource.ResourceStreamSourceFileSystem; 037 038/** 039 * Adapter for {@link IsisConfigurationBuilder}, loading the specified 040 * configuration resource (file) from the given {@link ResourceStreamSource}(s). 041 * 042 * <p> 043 * If a property is in multiple configuration resources then the latter 044 * resources will overwrite the former. 045 */ 046public class IsisConfigurationBuilderResourceStreams implements IsisConfigurationBuilder { 047 048 private static final Logger LOG = LoggerFactory.getLogger(IsisConfigurationBuilderResourceStreams.class); 049 050 static class ConfigurationResourceAndPolicy { 051 private final String configurationResource; 052 private final NotFoundPolicy notFoundPolicy; 053 054 public ConfigurationResourceAndPolicy(final String configurationResource, final NotFoundPolicy notFoundPolicy) { 055 this.configurationResource = configurationResource; 056 this.notFoundPolicy = notFoundPolicy; 057 } 058 059 public String getConfigurationResource() { 060 return configurationResource; 061 } 062 063 public NotFoundPolicy getNotFoundPolicy() { 064 return notFoundPolicy; 065 } 066 067 @Override 068 public String toString() { 069 return String.format("%s{%s}", configurationResource, notFoundPolicy); 070 } 071 } 072 073 private final Set<String> configurationResourcesFound = Sets.newLinkedHashSet(); 074 private final Set<String> configurationResourcesNotFound = Sets.newLinkedHashSet(); 075 private final ResourceStreamSource resourceStreamSource; 076 private final IsisConfigurationDefault configuration; 077 private final List<ConfigurationResourceAndPolicy> configurationResources = new ArrayList<ConfigurationResourceAndPolicy>(); 078 private boolean locked; 079 080 // //////////////////////////////////////////////////////////// 081 // Constructor, initialization 082 // //////////////////////////////////////////////////////////// 083 084 private static ResourceStreamSource createComposite(final ResourceStreamSource... resourceStreamSources) { 085 final ResourceStreamSourceChainOfResponsibility composite = new ResourceStreamSourceChainOfResponsibility(); 086 for (final ResourceStreamSource rss : resourceStreamSources) { 087 if (rss == null) { 088 continue; 089 } 090 composite.addResourceStreamSource(rss); 091 } 092 return composite; 093 } 094 095 public IsisConfigurationBuilderResourceStreams() { 096 this(ResourceStreamSourceFileSystem.create(ConfigurationConstants.DEFAULT_CONFIG_DIRECTORY)); 097 } 098 099 public IsisConfigurationBuilderResourceStreams(final ResourceStreamSource... resourceStreamSources) { 100 this(createComposite(resourceStreamSources)); 101 } 102 103 public IsisConfigurationBuilderResourceStreams(final ResourceStreamSource resourceStreamSource) { 104 this.resourceStreamSource = resourceStreamSource; 105 configuration = new IsisConfigurationDefault(resourceStreamSource); 106 } 107 108 /** 109 * May be overridden by subclasses if required. 110 */ 111 public void addDefaultConfigurationResources() { 112 addConfigurationResource(ConfigurationConstants.DEFAULT_CONFIG_FILE, NotFoundPolicy.FAIL_FAST); 113 addConfigurationResource(ConfigurationConstants.WEB_CONFIG_FILE, NotFoundPolicy.CONTINUE); 114 } 115 116 // //////////////////////////////////////////////////////////// 117 // ResourceStreamSource 118 // //////////////////////////////////////////////////////////// 119 120 @Override 121 public ResourceStreamSource getResourceStreamSource() { 122 return resourceStreamSource; 123 } 124 125 // //////////////////////////////////////////////////////////// 126 // populating or updating 127 // //////////////////////////////////////////////////////////// 128 129 /** 130 * Registers the configuration resource (usually, a file) with the specified 131 * name from the first {@link ResourceStreamSource} available. 132 * 133 * <p> 134 * If the configuration resource cannot be found then the provided 135 * {@link NotFoundPolicy} determines whether an exception is thrown or not. 136 * 137 * <p> 138 * Must be called before {@link #getConfiguration()}; the resource is 139 * actually read on {@link #getConfiguration()}. 140 */ 141 @Override 142 public synchronized void addConfigurationResource(final String configurationResource, final NotFoundPolicy notFoundPolicy) { 143 LOG.debug("looking for properties file " + configurationResource); 144 loadConfigurationResource(configuration, new ConfigurationResourceAndPolicy(configurationResource, notFoundPolicy)); 145 configurationResources.add(new ConfigurationResourceAndPolicy(configurationResource, notFoundPolicy)); 146 } 147 148 /** 149 * Adds additional property. 150 */ 151 @Override 152 public synchronized void add(final String key, final String value) { 153 if (locked) { 154 throw new IsisException("Configuration has been locked and cannot be changed"); 155 } 156 configuration.add(key, value); 157 } 158 159 public void lockConfiguration() { 160 locked = true; 161 } 162 163 // //////////////////////////////////////////////////////////// 164 // getConfiguration 165 // //////////////////////////////////////////////////////////// 166 167 /** 168 * Returns the current {@link IsisConfiguration configuration}. 169 */ 170 @Override 171 public synchronized IsisConfiguration getConfiguration() { 172 return configuration; 173 } 174 175 private void loadConfigurationResource(final IsisConfigurationDefault configuration, final ConfigurationResourceAndPolicy configResourceAndPolicy) { 176 final String configurationResource = configResourceAndPolicy.getConfigurationResource(); 177 final NotFoundPolicy notFoundPolicy = configResourceAndPolicy.getNotFoundPolicy(); 178 LOG.debug("checking availability of configuration resource: " + configurationResource + ", notFoundPolicy: " + notFoundPolicy); 179 loadConfigurationResource(configuration, configurationResource, notFoundPolicy); 180 } 181 182 /** 183 * Loads the configuration resource (usually, a file) with the specified 184 * name from the first {@link ResourceStreamSource} available. 185 * 186 * <p> 187 * If the configuration resource cannot be found then the provided 188 * {@link NotFoundPolicy} determines whether an exception is thrown or not. 189 */ 190 protected void loadConfigurationResource(final IsisConfigurationDefault configuration, final String configurationResource, final NotFoundPolicy notFoundPolicy) { 191 try { 192 final PropertiesReader propertiesReader = loadConfigurationResource(resourceStreamSource, configurationResource); 193 LOG.info("loading properties from " + configurationResource); 194 configuration.add(propertiesReader.getProperties()); 195 configurationResourcesFound.add(configurationResource); 196 return; 197 } catch (final IOException ignore) { } 198 if (notFoundPolicy == NotFoundPolicy.FAIL_FAST) { 199 throw new IsisException("failed to load '" + configurationResource + "'; tried using: " + resourceStreamSource.getName()); 200 } else { 201 configurationResourcesNotFound.add(configurationResource); 202 LOG.debug("'" + configurationResource + "' not found, but not needed"); 203 } 204 } 205 206 private PropertiesReader loadConfigurationResource(final ResourceStreamSource resourceStreamSource, final String configurationResource) throws IOException { 207 return new PropertiesReader(resourceStreamSource, configurationResource); 208 } 209 210 211 // TODO review this, should this option default to yes? 212 private void addShowExplorationOptionsIfNotSpecified(final IsisConfigurationDefault configuration) { 213 if (configuration.getString(ConfigurationConstants.SHOW_EXPLORATION_OPTIONS) == null) { 214 configuration.add(ConfigurationConstants.SHOW_EXPLORATION_OPTIONS, "yes"); 215 } 216 } 217 218 // //////////////////////////////////////////////////////////// 219 // Logging 220 // //////////////////////////////////////////////////////////// 221 222 @Override 223 public void dumpResourcesToLog() { 224 if (LOG.isInfoEnabled()) { 225 LOG.info("Configuration resources FOUND:"); 226 for (String resource : configurationResourcesFound) { 227 LOG.info("* " + resource); 228 } 229 LOG.info("Configuration resources NOT FOUND (but not needed):"); 230 for (String resource : configurationResourcesNotFound) { 231 LOG.info("* " + resource); 232 } 233 } 234 } 235 236 237 // //////////////////////////////////////////////////////////// 238 // Injectable 239 // //////////////////////////////////////////////////////////// 240 241 @Override 242 public void injectInto(final Object candidate) { 243 if (IsisConfigurationBuilderAware.class.isAssignableFrom(candidate.getClass())) { 244 final IsisConfigurationBuilderAware cast = IsisConfigurationBuilderAware.class.cast(candidate); 245 cast.setConfigurationBuilder(this); 246 } 247 } 248 249 @Override 250 public String toString() { 251 return Objects.toStringHelper(this).add("resourceStream", resourceStreamSource).add("configResources", configurationResources).toString(); 252 } 253 254}