All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.osgi.service.indexer.impl.RepoIndex Maven / Gradle / Ivy

package org.osgi.service.indexer.impl;

import static org.osgi.framework.FrameworkUtil.createFilter;

import java.io.File;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.net.URL;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Formatter;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import java.util.zip.Deflater;
import java.util.zip.GZIPOutputStream;

import org.osgi.framework.Filter;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.service.indexer.Capability;
import org.osgi.service.indexer.Requirement;
import org.osgi.service.indexer.ResourceAnalyzer;
import org.osgi.service.indexer.ResourceIndexer;
import org.osgi.service.indexer.impl.types.TypedValue;
import org.osgi.service.indexer.impl.util.AddOnlyList;
import org.osgi.service.indexer.impl.util.Indent;
import org.osgi.service.indexer.impl.util.Pair;
import org.osgi.service.indexer.impl.util.Tag;
import org.osgi.service.log.LogService;

/**
 * The repository indexer. See OSGi Enterprise Specification 5.0.0, chapter 132.
 */
public class RepoIndex implements ResourceIndexer {
	/**
	 * Name of the configuration variable for the increment (if not set then
	 * System.currentTimeMillis() is used)
	 */
	public static final String							REPOSITORY_INCREMENT_OVERRIDE	= "-repository.increment.override";

	/** the generic bundle analyzer */
	private final BundleAnalyzer						bundleAnalyzer;

	/** the OSGi Framework analyzer */
	private final OSGiFrameworkAnalyzer					frameworkAnalyzer;

	/** the Declarative Services analyzer */
	private final SCRAnalyzer							scrAnalyzer;

	/** the BluePrint analyzer */
	private final BlueprintAnalyzer						blueprintAnalyzer;

	/** the logger */
	private final LogService							log;

	/**
	 * the list of analyzer/filter pairs. The filter determines which resources
	 * can be analyzed
	 */
	private final List>	analyzers						= new LinkedList>();

	private final List						resolvers						= new ArrayList<>();

	/**
	 * Construct a default instance that uses a console logger.
	 */
	public RepoIndex() {
		this(new ConsoleLogSvc());
	}

	/**
	 * Constructor
	 * 
	 * @param log the log service to use
	 */
	public RepoIndex(LogService log) {
		this.log = log;

		this.bundleAnalyzer = new BundleAnalyzer(log);
		this.frameworkAnalyzer = new OSGiFrameworkAnalyzer(log);
		this.scrAnalyzer = new SCRAnalyzer(log);
		this.blueprintAnalyzer = new BlueprintAnalyzer(log);

		try {
			Filter allFilter = createFilter("(name=*.jar)");

			addAnalyzer(bundleAnalyzer, allFilter);
			addAnalyzer(frameworkAnalyzer, allFilter);
			addAnalyzer(scrAnalyzer, allFilter);
			addAnalyzer(blueprintAnalyzer, allFilter);
		} catch (InvalidSyntaxException e) {
			throw new ExceptionInInitializerError("Unexpected internal error compiling filter");
		}
	}

	/**
	 * @param analyzer the analyzer to add
	 * @param filter the filter that determines which resources can be analyzed
	 */
	public final void addAnalyzer(ResourceAnalyzer analyzer, Filter filter) {
		synchronized (analyzers) {
			analyzers.add(Pair.create(analyzer, filter));
		}
	}

	/**
	 * @param analyzer the analyzer to add
	 * @param filter the filter that determines which resources can be analyzed
	 */
	public final void removeAnalyzer(ResourceAnalyzer analyzer, Filter filter) {
		synchronized (analyzers) {
			analyzers.remove(Pair.create(analyzer, filter));
		}
	}

	/*
	 * See ResourceIndexer interface
	 */
	public void index(Set files, OutputStream out, Map config) throws Exception {
		if (config == null)
			config = new HashMap(0);

		Set filesToIndex = new TreeSet();
		if (files != null && !files.isEmpty()) {
			resolveDirectories(files, filesToIndex);
		}

		Indent indent;
		PrintWriter pw = null;
		try {
			String prettySetting = config.get(ResourceIndexer.PRETTY);
			String compressedSetting = config.get(ResourceIndexer.COMPRESSED);
			/**
			 * 
			 *  pretty compressed out-pretty out-compressed null null
			 * Indent.NONE true* null false Indent.NONE false null true
			 * Indent.NONE true false null Indent.PRETTY false* false false
			 * Indent.NONE false false true Indent.NONE true true null
			 * Indent.PRETTY false* true false Indent.PRETTY false true true
			 * Indent.PRETTY true * = original behaviour, before compressed was
			 * introduced
			 * 
*/ indent = (prettySetting == null || (!Boolean.parseBoolean(prettySetting) && compressedSetting != null)) ? Indent.NONE : Indent.PRETTY; boolean compressed = (prettySetting == null && compressedSetting == null) || Boolean.parseBoolean(compressedSetting); if (!compressed) { pw = new PrintWriter(new OutputStreamWriter(out, "UTF-8")); } else { pw = new PrintWriter(new GZIPOutputStream(out, Deflater.BEST_COMPRESSION)); } pw.print(Schema.XML_PROCESSING_INSTRUCTION); String stylesheet = config.get(STYLESHEET); if (stylesheet != null) { indent.print(pw); pw.printf(Schema.XML_STYLESHEET_INSTRUCTION, stylesheet, "text/xsl"); } Tag repoTag = new Tag(Schema.ELEM_REPOSITORY); String repoName = config.get(REPOSITORY_NAME); if (repoName == null) repoName = REPOSITORYNAME_DEFAULT; repoTag.addAttribute(Schema.ATTR_NAME, repoName); String increment = config.get(REPOSITORY_INCREMENT_OVERRIDE); if (increment == null) increment = Long.toString(System.currentTimeMillis()); repoTag.addAttribute(Schema.ATTR_INCREMENT, increment); repoTag.addAttribute(Schema.ATTR_XML_NAMESPACE, Schema.NAMESPACE); repoTag.printOpen(indent, pw, false); for (File file : filesToIndex) { try { Tag resourceTag = generateResource(file, config); resourceTag.print(indent.next(), pw); } catch (Exception e) { log(LogService.LOG_WARNING, MessageFormat.format("Could not index {0}, skipped ({1}).", file, e.getMessage()), null); } } repoTag.printClose(indent, pw); } finally { if (pw != null) { pw.flush(); pw.close(); } } } private void resolveDirectories(Set files, Set filesToIndex) { for (File file : files) { if (!file.isDirectory()) { filesToIndex.add(file); } else { File[] dirFiles = file.listFiles(); if (dirFiles.length > 0) { Set dirFilesSet = new LinkedHashSet(Arrays.asList(dirFiles)); resolveDirectories(dirFilesSet, filesToIndex); } } } } public void indexFragment(Set files, Writer out, Map config) throws Exception { PrintWriter pw; if (out instanceof PrintWriter) pw = (PrintWriter) out; else pw = new PrintWriter(out); for (File file : files) { try { Tag resourceTag = generateResource(file, config); resourceTag.print(Indent.PRETTY, pw); } catch (Exception e) { log(LogService.LOG_WARNING, MessageFormat.format("Could not index {0}, skipped ({1}).", file, e.getMessage()), null); } } } private Tag generateResource(File file, Map config) throws Exception { JarResource resource = new JarResource(file); List caps = new AddOnlyList(new LinkedList()); List reqs = new AddOnlyList(new LinkedList()); Tag resourceTag = new Tag(Schema.ELEM_RESOURCE); try { // Read config settings and save in thread local state if (config != null) { URL rootURL; String rootURLStr = config.get(ResourceIndexer.ROOT_URL); if (rootURLStr != null) { File rootDir = new File(rootURLStr); if (rootDir.isDirectory()) rootURL = rootDir.toURI().toURL(); else rootURL = new URL(rootURLStr); } else rootURL = new File(System.getProperty("user.dir")).toURI().toURL(); String urlTemplate = config.get(ResourceIndexer.URL_TEMPLATE); bundleAnalyzer.setStateLocal(new GeneratorState(rootURL.toURI().normalize(), urlTemplate, resolvers)); } else { bundleAnalyzer.setStateLocal(null); } // Iterate over the analyzers try { synchronized (analyzers) { for (Pair entry : analyzers) { ResourceAnalyzer analyzer = entry.getFirst(); Filter filter = entry.getSecond(); if (filter == null || filter.match(resource.getProperties())) { try { analyzer.analyzeResource(resource, caps, reqs); } catch (Exception e) { log(LogService.LOG_ERROR, MessageFormat.format("Error calling analyzer \"{0}\" on resource {1}.", analyzer.getClass().getName(), resource.getLocation()), e); StringWriter writer = new StringWriter(); Formatter comment = new Formatter(writer); comment.format( "Error calling analyzer \"%s\" on resource %s with message %s and stack: ", analyzer.getClass().getName(), resource.getLocation(), e); comment.close(); e.printStackTrace(new PrintWriter(writer)); resourceTag.addComment(writer.toString()); } } } } } finally { bundleAnalyzer.setStateLocal(null); } } finally { resource.close(); } for (Capability cap : caps) { Tag capTag = new Tag(Schema.ELEM_CAPABILITY); capTag.addAttribute(Schema.ATTR_NAMESPACE, cap.getNamespace()); appendAttributeAndDirectiveTags(capTag, cap.getAttributes(), cap.getDirectives()); resourceTag.addContent(capTag); } for (Requirement req : reqs) { Tag reqTag = new Tag(Schema.ELEM_REQUIREMENT); reqTag.addAttribute(Schema.ATTR_NAMESPACE, req.getNamespace()); appendAttributeAndDirectiveTags(reqTag, req.getAttributes(), req.getDirectives()); resourceTag.addContent(reqTag); } return resourceTag; } private void log(int level, String message, Throwable t) { if (log != null) { log.log(level, message, t); } else { PrintStream ps; switch (level) { case LogService.LOG_DEBUG : return; case LogService.LOG_INFO : ps = System.out; break; case LogService.LOG_WARNING : case LogService.LOG_ERROR : default : ps = System.err; break; } ps.println(message); if (t != null) { t.printStackTrace(ps); } } } private static void appendAttributeAndDirectiveTags(Tag parentTag, Map attribs, Map directives) { for (Entry attribEntry : attribs.entrySet()) { Tag attribTag = new Tag(Schema.ELEM_ATTRIBUTE); attribTag.addAttribute(Schema.ATTR_NAME, attribEntry.getKey()); TypedValue value = TypedValue.valueOf(attribEntry.getValue()); value.addTo(attribTag); parentTag.addContent(attribTag); } for (Entry directiveEntry : directives.entrySet()) { Tag directiveTag = new Tag(Schema.ELEM_DIRECTIVE); directiveTag.addAttribute(Schema.ATTR_NAME, directiveEntry.getKey()); directiveTag.addAttribute(Schema.ATTR_VALUE, directiveEntry.getValue()); parentTag.addContent(directiveTag); } } /** * Get the current analyzers */ public List getAnalyzers() { List list = new ArrayList(); for (Pair entry : analyzers) { list.add(entry.getFirst()); } return list; } /* * Index a file and return a resource for it. */ public IndexResult indexFile(File file) throws Exception { IndexResult result = new IndexResult(); result.resource = new JarResource(file); result.signature = getSignature(); synchronized (analyzers) { for (Pair entry : analyzers) { ResourceAnalyzer analyzer = entry.getFirst(); Filter filter = entry.getSecond(); if (filter == null || filter.match(result.resource.getProperties())) { analyzer.analyzeResource(result.resource, result.capabilities, result.requirements); } } } return result; } private long getSignature() { long value = 97; for (Pair ra : analyzers) { value *= 997 * ra.getFirst().getClass().getName().hashCode() + 13; } return value; } /** * Set a URL resolver that calculates the reference to the file This method * is deprecated as it forcibly sets the first resolver, overwriting the * previous one. This is to maintain backward compatibility with previous * versions */ @Deprecated public void setURLResolver(URLResolver resolver) { if (resolvers.isEmpty()) { addURLResolver(resolver); } else { this.resolvers.set(0, resolver); } } /** * Set a URL resolver that calculates the reference to the file This method * allows multiple resolvers to be added, each resolver will be called, and * will result in a separate content capability being created for the * resource */ public void addURLResolver(URLResolver resolver) { this.resolvers.add(resolver); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy