Java tutorial
/* * @(#)PropertiesQueryStore.java Jun 6, 2012 11:31:30 PM * * Copyright 2012 Radeon Systems * * 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 com.radeonsys.data.querystore.support.properties; import java.io.IOException; import java.io.InputStream; import java.util.InvalidPropertiesFormatException; import java.util.List; import java.util.Properties; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import com.google.common.io.Closeables; import com.radeonsys.data.querystore.QueryLoadException; import com.radeonsys.data.querystore.QueryStore; import com.radeonsys.data.querystore.support.AbstractHashMapQueryStore; import com.radeonsys.data.querystore.support.loader.ResourceLoader; import com.radeonsys.data.querystore.support.loader.ResourceNotFoundException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * An implementation of {@link QueryStore} which supports loading of * query definitions from properties resources. * * <p>Query definitions can be loaded from a pre-built instance of * {@link Properties} object. To use this feature, pass the pre-built * {@link Properties} to the {@link #PropertiesQueryStore(Properties)} * constructor.</p> * * <p>Query definitions can also be loaded from one or more XML properties * file resource using a {@link ResourceLoader}. To use this feature, pass * a list of locations of the XML properties resources and an instance of * {@link ResourceLoader} to be used to load the resource items.</p> * * <p>When used with XML properties resources loaded using the * {@link ResourceLoader}, callers must invoke the {@link #initialize()} * method before the first call to {@link #getQuery(String)}. The method * causes this implementation to read all query definitions off the XML * properties file resource and caches them.</p> * * <p>Calling the {@link #initialize()} is not required when using a * pre-built {@link Properties} with this implementation.</p> * * <p><b>NOTE:</b> This implementation only supports loading XML property * resources. It does not support properties files in the single line * format.</p> * * @see Properties * @see QueryStore * @see ResourceLoader * * @author oddjobsman * @since 1.0 */ public class PropertiesQueryStore extends AbstractHashMapQueryStore { private final Logger logger = LoggerFactory.getLogger(PropertiesQueryStore.class); /** * Stores a list of all resource locations to be processed */ private List<String> resourceLocations; /** * Stores a reference to the {@link ResourceLoader} to be used to * load the XML property resources */ private ResourceLoader loaderToUse; /** * Stores whether or not this query store is initialized */ private boolean storeInitialized = false; /** * Creates a new instance of {@code PropertiesQueryStore} reading * queries off the specified properties * * @param props reference to an instance of {@link Properties} * containing query definitions * * @throws IllegalArgumentException * if the specified properties instance is {@code null} */ public PropertiesQueryStore(Properties props) { if (logger.isTraceEnabled()) logger.trace("Initialized query store with predefined properties file."); copyQueriesToStore(props); storeInitialized(); } /** * Creates a new instance of {@code PropertiesQueryStore} which loads XML * properties resources from the specified locations using the * specified loader * * @param resourceLocations reference to an instance of {@link List} which contains * locations of the XML properties resources to load * @param loaderToUse reference to an instance of {@link ResourceLoader} which * must be used the XML properties resources */ public PropertiesQueryStore(List<String> resourceLocations, ResourceLoader loaderToUse) { if (logger.isTraceEnabled()) logger.trace("Initialized query store from specified resource locations."); this.resourceLocations = resourceLocations; this.loaderToUse = loaderToUse; } /** * Initializes this query store by loading query definitions from the specified * XML properties resources using the specified {@link ResourceLoader} instance * * @throws QueryLoadException * if there was an error loading query definitions from the specified resource locations */ public void initialize() { Preconditions.checkState(!storeInitialized, "This query store is already initialized"); Preconditions.checkState((resourceLocations != null && loaderToUse != null), "Cannot initialize query store without specifying resource locations or loader to use"); processResources(); } /* (non-Javadoc) * @see com.radeonsys.data.querystore.QueryStore#getQuery(java.lang.String) */ @Override public String getQuery(String nameOfQuery) { return getQueryInternal(nameOfQuery); } /** * Process all the resources specified while creating this store */ private void processResources() { if (logger.isTraceEnabled()) logger.trace("Attempting to process resources for queries"); if (resourceLocations.isEmpty()) return; for (String resourceLocation : resourceLocations) copyQueriesToStore(processResource(resourceLocation)); storeInitialized(); } private void storeInitialized() { storeInitialized = true; if (logger.isDebugEnabled()) logger.debug("Initialized query store using properties"); } /** * Processes a single resource item to extract the query definitions from the * resource * * @param resourceLocation the location of the resource item to be processed * * @return reference to an instance of {@link Properties} which contains query * definitions extracted from the resource item */ private Properties processResource(String resourceLocation) { if (logger.isTraceEnabled()) logger.trace(String.format("Processing resource: %s", resourceLocation)); InputStream is = null; final Properties props = new Properties(); try { is = loaderToUse.getBinaryResource(resourceLocation).getInput(); props.loadFromXML(is); } catch (ResourceNotFoundException e) { throw new QueryLoadException(String.format("The resource \"%s\" could not be found.", resourceLocation), e); } catch (InvalidPropertiesFormatException e) { if (logger.isWarnEnabled()) logger.warn(String.format("Encountered Invalid XML properties format in resource: %s", resourceLocation), e); throw new QueryLoadException(String.format( "The resource \"%s\" does not contain a valid XML properties data.", resourceLocation), e); } catch (IOException e) { if (logger.isWarnEnabled()) logger.warn(String.format("Encountered IO error while reading resource: %s", resourceLocation), e); throw new QueryLoadException( String.format("The resource \"%s\" could not be loaded due to an unexpected I/O error.", resourceLocation), e); } finally { Closeables.closeQuietly(is); } if (logger.isTraceEnabled()) logger.trace(String.format("Loaded %d queries from resource: %s", props.size(), resourceLocation)); return props; } /** * Copies queries from the specified properties object into this query * store * * @param props reference to an instance of {@link Properties} which * contains query definitions to copy * * @throws IllegalArgumentException * if the specified properties is {@code null} */ private final void copyQueriesToStore(Properties props) { Preconditions.checkArgument(props != null, "A valid set of properties must be specified."); if (props.isEmpty()) return; ImmutableMap<String, String> propMap = Maps.fromProperties(props); for (String queryName : propMap.keySet()) addQuery(queryName, propMap.get(queryName).trim()); if (logger.isTraceEnabled()) logger.trace(String.format("Copied %d queries into query store", props.size())); } }