202N/A/*
202N/A * CDDL HEADER START
202N/A *
202N/A * The contents of this file are subject to the terms of the
202N/A * Common Development and Distribution License (the "License").
202N/A * You may not use this file except in compliance with the License.
202N/A *
202N/A * See LICENSE.txt included in this distribution for the specific
202N/A * language governing permissions and limitations under the License.
202N/A *
202N/A * When distributing Covered Code, include this CDDL HEADER in each
202N/A * file and include the License file at LICENSE.txt.
202N/A * If applicable, add the following below this CDDL HEADER, with the
202N/A * fields enclosed by brackets "[]" replaced with your own identifying
202N/A * information: Portions Copyright [yyyy] [name of copyright owner]
202N/A *
202N/A * CDDL HEADER END
202N/A */
202N/A
202N/A/*
1127N/A * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
202N/A */
202N/Apackage org.opensolaris.opengrok.analysis;
202N/A
394N/Aimport java.io.IOException;
202N/Aimport java.io.InputStream;
921N/Aimport java.io.Reader;
202N/Aimport java.io.Writer;
202N/Aimport java.util.Arrays;
202N/Aimport java.util.Collections;
202N/Aimport java.util.List;
202N/Aimport org.opensolaris.opengrok.analysis.FileAnalyzer.Genre;
271N/Aimport org.opensolaris.opengrok.configuration.Project;
202N/Aimport org.opensolaris.opengrok.history.Annotation;
202N/A
202N/A/**
202N/A * Factory class which creates a {@code FileAnalyzer} object and
202N/A * provides information about this type of analyzers.
202N/A */
202N/Apublic class FileAnalyzerFactory {
271N/A
202N/A /** Cached analyzer object for the current thread (analyzer objects can be
202N/A * expensive to allocate). */
202N/A private final ThreadLocal<FileAnalyzer> cachedAnalyzer;
483N/A /** List of file names on which this kind of analyzer should be used. */
483N/A private final List<String> names;
202N/A /** List of file extensions on which this kind of analyzer should be
202N/A * used. */
202N/A private final List<String> suffixes;
202N/A /** List of magic strings used to recognize files on which this kind of
202N/A * analyzer should be used. */
202N/A private final List<String> magics;
202N/A /** List of matchers which delegate files to different types of
202N/A * analyzers. */
202N/A private final List<Matcher> matchers;
202N/A /** The content type for the files recognized by this kind of analyzer. */
202N/A private final String contentType;
202N/A /** The genre for files recognized by this kind of analyzer. */
202N/A private final Genre genre;
202N/A
202N/A /**
202N/A * Create an instance of {@code FileAnalyzerFactory}.
202N/A */
202N/A FileAnalyzerFactory() {
483N/A this(null, null, null, null, null, null);
202N/A }
202N/A
202N/A /**
202N/A * Construct an instance of {@code FileAnalyzerFactory}. This constructor
202N/A * should be used by subclasses to override default values.
202N/A *
483N/A * @param names list of file names to recognize (possibly {@code null})
202N/A * @param suffixes list of suffixes to recognize (possibly {@code null})
202N/A * @param magics list of magic strings to recognize (possibly {@code null})
202N/A * @param matcher a matcher for this analyzer (possibly {@code null})
202N/A * @param contentType content type for this analyzer (possibly {@code null})
202N/A * @param genre the genre for this analyzer (if {@code null}, {@code
202N/A * Genre.DATA} is used)
202N/A */
483N/A protected FileAnalyzerFactory(
483N/A String[] names, String[] suffixes, String[] magics,
271N/A Matcher matcher, String contentType,
271N/A Genre genre) {
202N/A cachedAnalyzer = new ThreadLocal<FileAnalyzer>();
483N/A this.names = asList(names);
202N/A this.suffixes = asList(suffixes);
202N/A this.magics = asList(magics);
202N/A if (matcher == null) {
202N/A this.matchers = Collections.emptyList();
202N/A } else {
202N/A this.matchers = Collections.singletonList(matcher);
202N/A }
202N/A this.contentType = contentType;
460N/A this.genre = (genre == null) ? Genre.DATA : genre;
202N/A }
202N/A
202N/A /**
202N/A * Helper method which wraps an array in a list.
202N/A *
202N/A * @param a the array to wrap ({@code null} means an empty array)
202N/A * @return a list which wraps the array
202N/A */
202N/A private static <T> List<T> asList(T[] a) {
202N/A if (a == null) {
202N/A return Collections.emptyList();
202N/A }
202N/A return Collections.unmodifiableList(Arrays.asList(a));
202N/A }
202N/A
202N/A /**
483N/A * Get the list of file names recognized by this analyzer (names must
483N/A * match exactly, ignoring case).
483N/A *
483N/A * @return list of file names
483N/A */
483N/A final List<String> getFileNames() {
483N/A return names;
483N/A }
483N/A
483N/A /**
202N/A * Get the list of file extensions recognized by this analyzer.
202N/A * @return list of suffixes
202N/A */
484N/A final List<String> getSuffixes() {
202N/A return suffixes;
202N/A }
202N/A
202N/A /**
202N/A * Get the list of magic strings recognized by this analyzer. If a file
202N/A * starts with one of these strings, an analyzer created by this factory
202N/A * should be used to analyze it.
202N/A *
202N/A * <p><b>Note:</b> Currently this assumes that the file is encoded with
202N/A * ISO-8859-1.
202N/A *
202N/A * @return list of magic strings
202N/A */
484N/A final List<String> getMagicStrings() {
202N/A return magics;
202N/A }
202N/A
202N/A /**
202N/A * Get matchers that map file contents to analyzer factories
202N/A * programmatically.
202N/A *
202N/A * @return list of matchers
202N/A */
484N/A final List<Matcher> getMatchers() {
202N/A return matchers;
202N/A }
202N/A
202N/A /**
202N/A * Get the content type (MIME type) for analyzers returned by this factory.
202N/A * @return content type (could be {@code null} if it is unknown)
202N/A */
484N/A final String getContentType() {
202N/A return contentType;
202N/A }
202N/A
202N/A /**
202N/A * The genre this analyzer factory belongs to.
202N/A * @return a genre
202N/A */
202N/A public final Genre getGenre() {
202N/A return genre;
202N/A }
202N/A
202N/A /**
202N/A * Get an analyzer. If the same thread calls this method multiple times on
202N/A * the same factory object, the exact same analyzer object will be returned
202N/A * each time. Subclasses should not override this method, but instead
202N/A * override the {@code newAnalyzer()} method.
202N/A *
202N/A * @return a {@code FileAnalyzer} instance
202N/A * @see #newAnalyzer()
202N/A */
202N/A public final FileAnalyzer getAnalyzer() {
202N/A FileAnalyzer fa = cachedAnalyzer.get();
202N/A if (fa == null) {
202N/A fa = newAnalyzer();
202N/A cachedAnalyzer.set(fa);
202N/A }
202N/A return fa;
202N/A }
202N/A
202N/A /**
202N/A * Create a new analyzer.
202N/A * @return an analyzer
202N/A */
202N/A protected FileAnalyzer newAnalyzer() {
202N/A return new FileAnalyzer(this);
202N/A }
202N/A
202N/A /**
202N/A * Interface for matchers which map file contents to analyzer factories.
202N/A */
202N/A protected interface Matcher {
271N/A
202N/A /**
202N/A * Try to match the file contents with an analyzer factory.
257N/A * If the method reads from the input stream, it must reset the
257N/A * stream before returning.
257N/A *
202N/A * @param contents the first few bytes of a file
257N/A * @param in the input stream from which the full file can be read
202N/A * @return an analyzer factory if the contents match, or {@code null}
202N/A * if they don't match any factory known by this matcher
202N/A */
257N/A FileAnalyzerFactory isMagic(byte[] contents, InputStream in)
257N/A throws IOException;
202N/A }
202N/A
202N/A /**
202N/A * Write a cross referenced HTML file. Reads the source from {@code in}.
202N/A * @param in input source
202N/A * @param out output xref writer
1127N/A * @param defs definitions for the file (could be {@code null})
202N/A * @param annotation annotation for the file (could be {@code null})
271N/A * @param project project the file belongs to (could be {@code null})
1190N/A * @throws java.io.IOException if an error occurs
202N/A */
1127N/A public void writeXref(Reader in, Writer out, Definitions defs, Annotation annotation, Project project)
271N/A throws IOException {
202N/A throw new UnsupportedOperationException("Not yet implemented");
202N/A }
202N/A}