1 8 package org.apache.avalon.phoenix.components.configuration; 9 10 import java.io.File ; 11 import java.io.IOException ; 12 13 import org.apache.avalon.excalibur.i18n.ResourceManager; 14 import org.apache.avalon.excalibur.i18n.Resources; 15 import org.apache.avalon.excalibur.io.FileUtil; 16 import org.apache.avalon.excalibur.property.PropertyException; 17 import org.apache.avalon.excalibur.property.PropertyUtil; 18 import org.apache.avalon.framework.CascadingRuntimeException; 19 import org.apache.avalon.framework.activity.Initializable; 20 import org.apache.avalon.framework.configuration.Configurable; 21 import org.apache.avalon.framework.configuration.Configuration; 22 import org.apache.avalon.framework.configuration.ConfigurationException; 23 import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder; 24 import org.apache.avalon.framework.configuration.DefaultConfigurationSerializer; 25 import org.apache.avalon.framework.context.Context; 26 import org.apache.avalon.framework.context.ContextException; 27 import org.apache.avalon.framework.context.Contextualizable; 28 import org.apache.avalon.framework.logger.AbstractLogEnabled; 29 import org.apache.avalon.phoenix.interfaces.ConfigurationRepository; 30 import org.apache.avalon.phoenix.interfaces.ConfigurationRepositoryMBean; 31 import org.apache.excalibur.configuration.ConfigurationUtil; 32 import org.apache.excalibur.configuration.merged.ConfigurationMerger; 33 import org.apache.excalibur.configuration.merged.ConfigurationSplitter; 34 35 import org.xml.sax.SAXException ; 36 37 56 public class FileSystemPersistentConfigurationRepository extends AbstractLogEnabled 57 implements ConfigurationRepository, Contextualizable, Configurable, Initializable, 58 ConfigurationRepositoryMBean 59 { 60 private static final Resources REZ = 61 ResourceManager.getPackageResources( FileSystemPersistentConfigurationRepository.class ); 62 63 private final DefaultConfigurationRepository m_persistedConfigurations = 64 new DefaultConfigurationRepository(); 65 private final DefaultConfigurationRepository 66 m_transientConfigurations = new DefaultConfigurationRepository(); 67 private final DefaultConfigurationRepository 68 m_mergedConfigurations = new DefaultConfigurationRepository(); 69 70 private Context m_context; 71 72 private File m_storageDirectory; 73 74 public void contextualize( Context context ) 75 throws ContextException 76 { 77 m_context = context; 78 } 79 80 public void configure( final Configuration configuration ) throws ConfigurationException 81 { 82 this.m_storageDirectory = new File ( constructStoragePath( configuration ) ); 83 84 try 85 { 86 FileUtil.forceMkdir( this.m_storageDirectory ); 87 } 88 catch( IOException e ) 89 { 90 final String message = REZ.getString( "config.error.dir.invalid", 91 this.m_storageDirectory ); 92 93 throw new ConfigurationException( message, e ); 94 95 } 96 } 97 98 private String constructStoragePath( final Configuration configuration ) 99 throws ConfigurationException 100 { 101 final String path = 102 configuration.getChild( "storage-directory" ).getValue( "${phoenix.home}/conf/apps" ); 103 104 try 105 { 106 final Object opath = PropertyUtil.resolveProperty( path, m_context, false ); 107 108 if( opath instanceof String ) 109 { 110 return FileUtil.normalize( ( String ) opath ); 111 } 112 else 113 { 114 final String message = REZ.getString( "config.error.nonstring", 115 opath.getClass().getName() ); 116 117 throw new ConfigurationException( message ); 118 } 119 } 120 catch( PropertyException e ) 121 { 122 final String message = REZ.getString( "config.error.missingproperty", 123 configuration.getLocation() ); 124 125 throw new ConfigurationException( message, e ); 126 } 127 } 128 129 public void initialize() 130 throws Exception 131 { 132 loadConfigurations(); 133 } 134 135 private void loadConfigurations() 136 throws IOException , SAXException , ConfigurationException 137 { 138 final File [] apps = m_storageDirectory.listFiles( new ConfigurationDirectoryFilter() ); 139 140 for( int i = 0; i < apps.length; i++ ) 141 { 142 loadConfigurations( apps[i] ); 143 } 144 } 145 146 private void loadConfigurations( File appPath ) 147 throws IOException , SAXException , ConfigurationException 148 { 149 final DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(); 150 final String app = appPath.getName(); 151 final File [] blocks = appPath.listFiles( new ConfigurationFileFilter() ); 152 153 for( int i = 0; i < blocks.length; i++ ) 154 { 155 final String block = 156 blocks[i].getName().substring( 0, blocks[i].getName().indexOf( ".xml" ) ); 157 158 m_persistedConfigurations.storeConfiguration( app, 159 block, 160 builder.buildFromFile( blocks[i] ) ); 161 162 if( getLogger().isDebugEnabled() ) 163 getLogger().debug( "Loaded persistent configuration [app: " + app 164 + ", block: " + block + "]" ); 165 } 166 } 167 168 private void persistConfiguration( final String application, 169 final String block, 170 final Configuration configuration ) 171 throws SAXException , IOException , ConfigurationException 172 { 173 final DefaultConfigurationSerializer serializer = new DefaultConfigurationSerializer(); 174 final File directory = new File ( this.m_storageDirectory, application ); 175 176 FileUtil.forceMkdir( directory ); 177 178 if( getLogger().isDebugEnabled() ) 179 getLogger().debug( "Serializing configuration to disk [app: " + application 180 + ", block: " + block + "]" ); 181 182 serializer.setIndent( true ); 183 serializer.serializeToFile( new File ( directory, block + ".xml" ), configuration ); 184 } 185 186 public void removeConfiguration( String application, String block ) 187 throws ConfigurationException 188 { 189 m_transientConfigurations.removeConfiguration( application, block ); 190 m_mergedConfigurations.removeConfiguration( application, block ); 191 } 192 193 public synchronized void storeConfiguration( final String application, 194 final String block, 195 final Configuration configuration ) 196 throws ConfigurationException 197 { 198 199 if( m_transientConfigurations.hasConfiguration( application, block ) ) 200 { 201 if( !ConfigurationUtil.equals( configuration, getConfiguration( application, block ) ) ) 202 { 203 final Configuration layer = 204 ConfigurationSplitter.split( configuration, 205 getConfiguration( application, 206 block, 207 m_transientConfigurations ) ); 208 209 m_persistedConfigurations.storeConfiguration( application, block, layer ); 210 m_mergedConfigurations.removeConfiguration( application, block ); 211 212 try 213 { 214 persistConfiguration( application, block, layer ); 215 } 216 catch( SAXException e ) 217 { 218 final String message = 219 REZ.getString( "config.error.persist", application, block ); 220 221 throw new ConfigurationException( message, e ); 222 } 223 catch( IOException e ) 224 { 225 final String message = 226 REZ.getString( "config.error.persist", application, block ); 227 228 throw new ConfigurationException( message, e ); 229 } 230 } 231 } 232 else 233 { 234 m_transientConfigurations.storeConfiguration( application, block, configuration ); 235 } 236 } 237 238 public synchronized Configuration getConfiguration( final String application, 239 final String block ) 240 throws ConfigurationException 241 { 242 if( m_mergedConfigurations.hasConfiguration( application, block ) ) 243 { 244 return m_mergedConfigurations.getConfiguration( application, block ); 245 } 246 else 247 { 248 final Configuration configuration = createMergedConfiguration( application, block ); 249 250 m_mergedConfigurations.storeConfiguration( application, block, configuration ); 251 252 return configuration; 253 } 254 } 255 256 private Configuration createMergedConfiguration( final String application, 257 final String block ) 258 throws ConfigurationException 259 { 260 final Configuration t = getConfiguration( application, block, m_transientConfigurations ); 261 final Configuration p = getConfiguration( application, block, m_persistedConfigurations ); 262 263 if( null == t && p == null ) 264 { 265 final String message = REZ.getString( "config.error.noconfig", block, application ); 266 267 throw new ConfigurationException( message ); 268 } 269 else if( null == t ) 270 { 271 return p; 272 } 273 else if( null == p ) 274 { 275 return t; 276 } 277 else 278 { 279 return ConfigurationMerger.merge( p, t ); 280 } 281 } 282 283 private Configuration getConfiguration( final String application, 284 final String block, 285 final DefaultConfigurationRepository repository ) 286 { 287 if( repository.hasConfiguration( application, block ) ) 288 { 289 try 290 { 291 return repository.getConfiguration( application, block ); 292 } 293 catch( ConfigurationException e ) 294 { 295 final String message = REZ.getString( "config.error.noconfig", block, application ); 296 297 throw new CascadingRuntimeException( message, e ); 298 } 299 } 300 else 301 { 302 return null; 303 } 304 } 305 306 public boolean hasConfiguration( String application, String block ) 307 { 308 return m_mergedConfigurations.hasConfiguration( application, block ) 309 || m_transientConfigurations.hasConfiguration( application, block ) 310 || m_persistedConfigurations.hasConfiguration( application, block ); 311 } 312 } 313 | Popular Tags |