/*
* Copyright (c) OSGi Alliance (2002, 2006, 2007). All Rights Reserved.
*
* 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 org.osgi.impl.bundle.bindex.cli;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.URL;
import java.nio.file.Files;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.jar.Manifest;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.osgi.framework.BundleContext;
import org.osgi.framework.launch.Framework;
import org.osgi.service.indexer.ResourceAnalyzer;
import org.osgi.service.indexer.ResourceIndexer;
import org.osgi.service.indexer.impl.KnownBundleAnalyzer;
import org.osgi.service.indexer.impl.RepoIndex;
import org.osgi.util.tracker.ServiceTracker;
import de.kalpatec.pojosr.framework.PojoServiceRegistryFactoryImpl;
import de.kalpatec.pojosr.framework.launch.ClasspathScanner;
import de.kalpatec.pojosr.framework.launch.PojoServiceRegistryFactory;
@SuppressWarnings("restriction")
public class Index {
/** the program name */
static final String PROGRAM_NAME = "repoindex";
public static final String DEFAULT_FILENAME_UNCOMPRESSED = "index.xml";
public static final String DEFAULT_FILENAME_COMPRESSED = DEFAULT_FILENAME_UNCOMPRESSED + ".gz";
/**
* Main entry point. See -help for options.
*
* @param args Program arguments
*/
public static void main(String args[]) {
try {
// Configure PojoSR
Map<String,Object> pojoSrConfig = new HashMap<String,Object>();
pojoSrConfig.put(PojoServiceRegistryFactory.BUNDLE_DESCRIPTORS, new ClasspathScanner());
// Start PojoSR 'framework'
Framework framework = new PojoServiceRegistryFactoryImpl().newFramework(pojoSrConfig);
framework.init();
framework.start();
// Look for indexer and run index generation
ServiceTracker<ResourceIndexer,ResourceIndexer> tracker = new ServiceTracker<ResourceIndexer,ResourceIndexer>(
framework.getBundleContext(), ResourceIndexer.class, null);
tracker.open();
ResourceIndexer index = tracker.waitForService(1000);
if (index == null)
throw new IllegalStateException("Timed out waiting for ResourceIndexer service.");
// Process arguments
Set<File> fileList = new LinkedHashSet<File>();
Map<String,String> config = new HashMap<String,String>();
File outputFile = processArgs(args, System.err, config, fileList, framework.getBundleContext());
if (outputFile == null) {
System.exit(1);
}
boolean verbose = Boolean.parseBoolean(config.get(ResourceIndexer.VERBOSE));
if (verbose) {
printCopyright(System.err);
}
try (@SuppressWarnings("null")
OutputStream fos = Files.newOutputStream(outputFile.toPath())) {
index.index(fileList, fos, config);
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
System.err.println(e.getMessage());
System.exit(1);
}
// We really need to ensure all non-daemon threads -- which may have
// been started by a bundle -- are terminated.
System.exit(0);
}
private static File processArgs(String[] args, PrintStream err, Map<String,String> config,
Collection< ? super File> fileList, BundleContext context) throws Exception {
/*
* Parse the command line
*/
CommandLineOptions commandLineOptions = new CommandLineOptions();
CmdLineParser parser = new CmdLineParser(commandLineOptions);
try {
parser.parseArgument(args);
} catch (CmdLineException e) {
err.printf("Error during command-line parsing: %s%n", e.getLocalizedMessage());
commandLineOptions.help = true;
}
/*
* Process command-line options
*/
/* print usage when so requested and exit */
if (commandLineOptions.help) {
try {
/* can't be covered by a test */
int cols = Integer.parseInt(System.getenv("COLUMNS")); //$NON-NLS-1$
if (cols > 80) {
parser.setUsageWidth(cols);
}
} catch (NumberFormatException e) {
/* swallow, can't be covered by a test */
}
CommandLineOptions.usage(err, PROGRAM_NAME, parser);
return null;
}
KnownBundleAnalyzer knownBundleAnalyzer = null;
config.put(ResourceIndexer.REPOSITORY_NAME, commandLineOptions.repositoryName);
if (commandLineOptions.stylesheetURL != null) {
config.put(ResourceIndexer.STYLESHEET, commandLineOptions.stylesheetURL.toString());
}
File output = commandLineOptions.outputFile;
if (commandLineOptions.verbose) {
config.put(ResourceIndexer.VERBOSE, Boolean.TRUE.toString());
}
if (commandLineOptions.rootURL != null) {
config.put(ResourceIndexer.ROOT_URL, commandLineOptions.rootURL.toString());
}
config.put(ResourceIndexer.URL_TEMPLATE, commandLineOptions.resourceUrlTemplate);
if (commandLineOptions.licenseURL != null) {
config.put(ResourceIndexer.LICENSE_URL, commandLineOptions.licenseURL.toString());
}
if (commandLineOptions.pretty) {
config.put(ResourceIndexer.PRETTY, Boolean.TRUE.toString());
}
if (commandLineOptions.overrideBuiltinKnownBundles) {
knownBundleAnalyzer = new KnownBundleAnalyzer(new Properties());
}
File knownBundlesExtraFile = commandLineOptions.knownBundlePropertiesFile;
if (commandLineOptions.incrementOverride) {
config.put(RepoIndex.REPOSITORY_INCREMENT_OVERRIDE, "");
}
if (commandLineOptions.fileList.isEmpty()) {
fileList.clear();
} else {
for (File file : commandLineOptions.fileList) {
fileList.add(new File(file.toURI().normalize().getPath()));
}
}
if (knownBundleAnalyzer == null)
knownBundleAnalyzer = new KnownBundleAnalyzer();
if (knownBundlesExtraFile != null) {
Properties props = loadPropertiesFile(knownBundlesExtraFile);
knownBundleAnalyzer.setKnownBundlesExtra(props);
}
context.registerService(ResourceAnalyzer.class.getName(), knownBundleAnalyzer, null);
return output;
}
private static Properties loadPropertiesFile(File knownBundles) throws FileNotFoundException, IOException {
Properties props = new Properties();
try (InputStream stream = Files.newInputStream(knownBundles.toPath())) {
props.load(stream);
}
return props;
}
public static void printCopyright(PrintStream out) throws IOException {
String version = "";
String copyright = "";
Enumeration<URL> urls = Index.class.getClassLoader().getResources("META-INF/MANIFEST.MF");
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
Manifest m = new Manifest(url.openStream());
String bsn = m.getMainAttributes().getValue("Bundle-SymbolicName");
if (bsn != null && bsn.equals("org.osgi.impl.bundle.repoindex.cli")) {
version = m.getMainAttributes().getValue("Bundle-Version");
copyright = m.getMainAttributes().getValue("Bundle-Copyright");
break;
}
}
out.println("RepoIndex | Resource Indexer v" + version);
out.println(copyright);
}
}