/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.stanbol.commons.solr.managed.util; import java.io.BufferedInputStream; import java.io.File; import java.io.InputStream; import org.apache.commons.compress.archivers.ArchiveException; import org.apache.commons.compress.archivers.ArchiveInputStream; import org.apache.commons.compress.archivers.ArchiveStreamFactory; import org.apache.commons.compress.compressors.CompressorException; import org.apache.commons.compress.compressors.CompressorStreamFactory; import org.apache.commons.compress.compressors.FileNameUtil; import org.apache.commons.io.FilenameUtils; import org.apache.solr.core.SolrCore; import org.apache.stanbol.commons.solr.SolrConstants; import org.apache.stanbol.commons.solr.managed.IndexMetadata; import org.apache.stanbol.commons.solr.managed.ManagedIndexState; import org.apache.stanbol.commons.solr.utils.ConfigUtils; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public final class ManagementUtils { /** * Private constructor to restrict instantiation */ private ManagementUtils() {} /** * The logger */ private static final Logger log = LoggerFactory.getLogger(ManagementUtils.class); /** * Substitutes ${property.name} with the values retrieved via <ul> * <li> {@link BundleContext#getProperty(String)} or * <li> {@link System#getProperty(String, String)} if the parsed * {@link BundleContext} is <code>null</code> * </ul> * Substitutes with an empty string if the property is not present. If * the substitution does not end with {@link File#separatorChar}, than it is * appended to allow easily creating paths relative to root directory available * as property regardless if the property includes/excludes the final * separator char. * <p> * Nested substitutions are NOT supported. However multiple substitutions are supported. * <p> * If someone knows a default implementation feel free to replace! * * @param value * the value to substitute * @param bundleContext * If not <code>null</code> the {@link BundleContext#getProperty(String)} is used instead of * the {@link System#getProperty(String)}. By that it is possible to use OSGI only properties * for substitution. * @return the substituted value */ public static String substituteProperty(String value, BundleContext bundleContext) { int prevAt = 0; int foundAt = 0; StringBuilder substitution = new StringBuilder(); while ((foundAt = value.indexOf("${", prevAt)) >= prevAt) { substitution.append(value.substring(prevAt, foundAt)); String propertyName = value.substring(foundAt + 2, value.indexOf('}', foundAt)); String propertyValue = bundleContext == null ? // if no bundleContext is available System.getProperty(propertyName) : // use the System properties bundleContext.getProperty(propertyName); if(propertyValue != null) { substitution.append(propertyValue); if(propertyValue.charAt(propertyValue.length()-1) != File.separatorChar){ substitution.append(File.separatorChar); } } //else nothing to append prevAt = foundAt + propertyName.length() + 3; // +3 -> "${}".length } substitution.append(value.substring(prevAt, value.length())); return substitution.toString(); } /** * An instance of the {@link ArchiveStreamFactory} */ public static final ArchiveStreamFactory archiveStreamFactory = new ArchiveStreamFactory(); /** * An instance of the compressor stream factory */ public static final CompressorStreamFactory compressorStreamFactory = new CompressorStreamFactory(); /** * Tries to create an {@link ArchiveInputStream} based on the parsed {@link InputStream}. * First the provided resource name is used to detect the type of the archive. * if that does not work, or the parsed resource name is <code>null</code> the * stream is created by using the auto-detection of the archive type. * @param resourceName the name of the resource or <code>null</code> * @param is the {@link InputStream} * @return the {@link ArchiveInputStream} * @throws ArchiveException if the {@link InputStream} does not represented any * supported Archive type */ public static ArchiveInputStream getArchiveInputStream(String resourceName, InputStream is) throws ArchiveException{ if(is == null){ return null; } String extension = resourceName == null ? null : FilenameUtils.getExtension(resourceName); if(!is.markSupported()){ is = new BufferedInputStream(is); } InputStream as; if(!"zip".equalsIgnoreCase(extension)){ //if not a zip file (the default) //we need to first check if this is a compressed stream try { as = compressorStreamFactory.createCompressorInputStream(extension,is); extension = "tar"; // assume tar archives } catch (CompressorException e) { try { as = compressorStreamFactory.createCompressorInputStream(is); extension = "tar"; // assume tar archives } catch (CompressorException e1) { //not a compression stream? as = is; } } } else { //zip ... this is already an archive stream as = is; } if(extension != null){ try { return archiveStreamFactory.createArchiveInputStream(extension, as); } catch (ArchiveException e) { //ignore } } //try to detect return archiveStreamFactory.createArchiveInputStream(is); } /** * Getter for the name of the index within the current * {@link IndexMetadata#getArchive() archive} set to load the index data * from. If no archive is set (e.g. if the {@link ArchiveInputStream} was * directly parsed, than the {@link IndexMetadata#getIndexName() index name} * directly is used as default. * @param metadata the {@link IndexMetadata} * @return the name of the index within the indexArchive used to load the * data from. In other words the relative path to the index data within the * index archive. */ public static String getArchiveCoreName(final IndexMetadata metadata) { String name = metadata.getIndexName(); String archiveCoreName = metadata.getArchive(); if(archiveCoreName == null){ archiveCoreName = name; } else { //the name of the core in the archive MUST BE the same as //the name of the archive excluding .solrindex.{archive-format} int split = archiveCoreName.indexOf('.'); if(split>0){ archiveCoreName = archiveCoreName.substring(0,split); } } return archiveCoreName; } // /** // * Parses the name of the Core from an IndexReference (file url, file path, // * index name or server:indexname) // * @param indexRef the parsed indexRef // * @return // */ // public static String getCoreNameForIndexRef(String indexRef,String serverName) { // // String[] parsedRef = ConfigUtils.parseSolrServerReference(indexRef); // String coreName; // if(parsedRef[0] != null && !parsedRef[0].equals(serverName)){ // coreName = null; //other server // } else { // coreName = parsedRef[1]; // if(coreName == null || coreName.isEmpty()){ // log.warn("The parsed index reference '"+indexRef+"' does not define a valid core name!"); // } // } // return coreName; // } /** * Creates and initialises a {@link IndexMetadata} instance based on the * parsed {@link SolrCore} * @param core the {@link SolrCore} * @param serverName the name of the server * @return the initialised {@link IndexMetadata} */ public static IndexMetadata getMetadata(SolrCore core, String serverName){ if(core == null){ return null; } IndexMetadata metadata = new IndexMetadata(); if(serverName != null){ metadata.setServerName(serverName); } metadata.setSynchronized(false); updateMetadata(metadata, core); return metadata; } /** * Updates the parsed {@link IndexMetadata} instance based on the * properties of the parsed {@link SolrCore}.<p> * This sets the state, index name and the directory. * @param metadata the {@link IndexMetadata} to update * @param core the core */ public static void updateMetadata(IndexMetadata metadata, SolrCore core){ if(metadata == null || core == null){ return; } metadata.setState(ManagedIndexState.ACTIVE); metadata.setIndexName(core.getName()); metadata.setDirectory(core.getCoreDescriptor().getInstanceDir()); } /** * Updates the parsed metadata based on the properties of the * {@link ServiceReference}.<p> * This updates the index name, server name, and the directory value based * on the corresponding keys as defined in {@link SolrConstants} * @param metadata the metadata to update * @param coreRef the ServiceReference used to update the metadata */ public static void updateMetadata(IndexMetadata metadata, ServiceReference coreRef){ if(metadata == null || coreRef == null){ return; } // if(SolrCore.class.getName().equals(coreRef.getProperty(Constants.OBJECTCLASS))){ String value = (String)coreRef.getProperty(SolrConstants.PROPERTY_CORE_DIR); if(value != null){ metadata.setDirectory(value); } value = (String) coreRef.getProperty(SolrConstants.PROPERTY_CORE_NAME); if(value != null){ metadata.setIndexName(value); } value = (String) coreRef.getProperty(SolrConstants.PROPERTY_SERVER_NAME); if(value != null){ metadata.setServerName(value); } // } //else parsed service Reference does not refer to a SolrCore } }