package net.typedrest.vaadin.views;

import com.google.common.eventbus.EventBus;
import net.typedrest.*;
import net.typedrest.vaadin.events.*;
import net.typedrest.vaadin.forms.*;
import com.vaadin.data.Validator;
import com.vaadin.ui.*;
import com.vaadin.ui.themes.ValoTheme;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.apache.http.HttpStatus;
import org.vaadin.dialogs.ConfirmDialog;

/**
 * Component for showing or updating an existing element represented by an
 * {@link ElementEndpoint}.
 *
 * @param <TEntity> The type of entity to represent.
 */
public class ElementView<TEntity>
        extends AbstractElementView<TEntity, ElementEndpoint<TEntity>> {

    protected final Button deleteButton = new Button("Delete", x -> delete()) {
        {
            addStyleName(ValoTheme.BUTTON_DANGER);
        }
    };

    /**
     * Creates a new REST element component.
     *
     * @param endpoint The REST endpoint this component operates on.
     * @param eventBus Used to send event between components.
     * @param entityForm A component for viewing/modifying entity instances.
     */
    public ElementView(ElementEndpoint<TEntity> endpoint, EventBus eventBus, EntityForm<TEntity> entityForm) {
        super(endpoint, eventBus, entityForm);

        buttonsLayout.addComponent(deleteButton);
    }

    /**
     * Creates a new REST element component.
     *
     * @param endpoint The REST endpoint this component operates on.
     * @param eventBus Used to send event between components.
     */
    public ElementView(ElementEndpoint<TEntity> endpoint, EventBus eventBus) {
        this(endpoint, eventBus, new AutoEntityForm<>(endpoint.getEntityType()));
    }

    @Override
    protected void onLoad()
            throws IOException, IllegalArgumentException, IllegalAccessException, FileNotFoundException, IllegalStateException {
        TEntity entity = endpoint.read();
        setCaption(entity.toString());
        entityForm.setEntity(entity);

        endpoint.isSetAllowed().ifPresent(this::setSaveEnabled);
        endpoint.isDeleteAllowed().ifPresent(this::setDeleteEnabled);
    }

    /**
     * Controls whether a save button is shown and fields are editable.
     *
     * @param val Turns the feature on or off.
     */
    public void setSaveEnabled(boolean val) {
        saveButton.setVisible(val);
        setReadOnly(!val);
        entityForm.setReadOnly(!val);
    }

    @Override
    protected void onSave()
            throws IOException, IllegalArgumentException, IllegalAccessException, FileNotFoundException, IllegalStateException, Validator.InvalidValueException {
        endpoint.set(entityForm.getEntity());
        eventBus.post(new ElementUpdatedEvent<>(endpoint));
    }

    /**
     * Controls whether a delete button is shown.
     *
     * @param val Turns the feature on or off.
     */
    public void setDeleteEnabled(boolean val) {
        deleteButton.setVisible(val);
    }

    /**
     * Deletes the element.
     */
    protected void delete() {
        String question = "Are you sure you want to delete " + getCaption() + "?";
        ConfirmDialog.show(getUI(), question, (ConfirmDialog cd) -> {
            if (cd.isConfirmed()) {
                try {
                    onDelete();
                    close();
                } catch (IOException | IllegalArgumentException | IllegalAccessException | IllegalStateException ex) {
                    onError(ex);
                } catch (RuntimeException ex) {
                    // Must explicitly send unhandled exceptions to error handler.
                    // Would otherwise get swallowed silently within callback handler.
                    getUI().getErrorHandler().error(new com.vaadin.server.ErrorEvent(ex));
                }
            }
        });
    }

    /**
     * Handler for deleting the element.
     *
     * @throws IOException Network communication failed.
     * @throws IllegalArgumentException {@link HttpStatus#SC_BAD_REQUEST}
     * @throws IllegalAccessException {@link HttpStatus#SC_UNAUTHORIZED} or
     * {@link HttpStatus#SC_FORBIDDEN}
     * @throws FileNotFoundException {@link HttpStatus#SC_NOT_FOUND} or
     * {@link HttpStatus#SC_GONE}
     * @throws IllegalStateException {@link HttpStatus#SC_CONFLICT}
     * @throws RuntimeException Other non-success status code.
     */
    protected void onDelete()
            throws IOException, IllegalArgumentException, IllegalAccessException, FileNotFoundException, IllegalStateException {
        endpoint.delete();
        eventBus.post(new ElementDeletedEvent<>(endpoint));
    }
}


/**
 * Copyright (C) 2015 Michael Schnell. All rights reserved.
 * http://www.fuin.org/
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 3 of the License, or (at your option) any
 * later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library. If not, see http://www.gnu.org/licenses/.
 */
package org.fuin.srcgen4j.core.velocity;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.validation.Valid;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

import org.fuin.objects4j.common.Contract;
import org.fuin.objects4j.vo.TrimmedNotEmpty;
import org.fuin.utils4j.Utils4J;

/**
 * File to produce.
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "target-file")
public final class TargetFile implements Serializable, Comparable<TargetFile> {

    private static final long serialVersionUID = 1L;

    @TrimmedNotEmpty
    @XmlAttribute
    private String path;

    @TrimmedNotEmpty
    @XmlAttribute
    private String name;

    @Valid
    @XmlElement(name = "argument")
    private List<Argument> arguments;

    /**
     * Default constructor for deserialization.
     */
    TargetFile() {
        super();
    }

    /**
     * Constructor with all data.
     *
     * @param path
     *            Path without filename or NULL.
     * @param name
     *            Name without path - Cannot be NULL.
     * @param args
     *            Arguments for the template or NULL.
     */
    public TargetFile(final String path, final String name, final Argument... args) {
        super();
        Contract.requireArgNotNull("name", name);
        this.path = path;
        this.name = name;

        if (args != null) {
            this.arguments = new ArrayList<Argument>();
            for (final Argument arg : args) {
                this.arguments.add(arg);
            }
        }

    }

    /**
     * Returns the relative path of the target file.
     *
     * @return Path or NULL.
     */
    public final String getPath() {
        return path;
    }

    /**
     * Returns the name of the target file.
     *
     * @return Name without path - Never NULL.
     */
    public final String getName() {
        return name;
    }

    /**
     * Returns path and name.
     *
     * @return Relative path and name.
     */
    public final String getPathAndName() {
        if (path == null) {
            return name;
        }
        return path + "/" + name;
    }

    /**
     * Returns a list of arguments to use.
     *
     * @return Arguments for the template or NULL.
     */
    public final List<Argument> getArguments() {
        return arguments;
    }

    // CHECKSTYLE:OFF Generated code
    @Override
    public final int hashCode() {
        final int prime = 31;
        int result = 1;
        result = (prime * result) + ((path == null) ? 0 : path.hashCode());
        result = (prime * result) + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    @Override
    public final boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final TargetFile other = (TargetFile) obj;
        if (path == null) {
            if (other.path != null) {
                return false;
            }
        } else if (!path.equals(other.path)) {
            return false;
        }
        if (name == null) {
            if (other.name != null) {
                return false;
            }
        } else if (!name.equals(other.name)) {
            return false;
        }
        return true;
    }

    // CHECKSTYLE:ON

    @Override
    public final int compareTo(final TargetFile other) {
        return getPathAndName().compareTo(other.getPathAndName());
    }

    /**
     * Replaces variables (if defined) in the path, name and arguments.
     *
     * @param vars
     *            Variables to use.
     */
    public final void init(final Map<String, String> vars) {
        path = Utils4J.replaceVars(path, vars);
        name = Utils4J.replaceVars(name, vars);
        if (arguments != null) {
            for (final Argument argument : arguments) {
                argument.init(vars);
            }
        }
    }

}


/*
 * Copyright (c) 2002 Cunningham & Cunningham, Inc.
 * Copyright (c) 2009-2015 by Jochen Wierum & Cologne Intelligence
 *
 * This file is part of FitGoodies.
 *
 * FitGoodies is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * FitGoodies is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with FitGoodies.  If not, see <http://www.gnu.org/licenses/>.
*/

package de.cologneintelligence.fitgoodies.file;

import java.io.*;

/**
 * Represents a file and provides information about it.
 */
public class FileInformation {

	private final File file;

	/**
	 * Generates a new information object.
     *
     * @param file File object to wrap
	 */
	public FileInformation(final File file) {
		this.file = file;
	}

	/**
	 * Opens the file and returns a {@code BufferedReader} object using
	 * the given encoding.
	 *
	 * @param encoding the encoding to use
	 * @return the open file as {@code BufferdReader}
	 * @throws IOException thrown if the file could not be read
	 */
	public BufferedReader openBufferedReader(final String encoding) throws IOException {
		final InputStream fis = openInputStream();
		final InputStreamReader isr = new InputStreamReader(fis, encoding);
		return new BufferedReader(isr);
	}

	/**
	 * Alias to {@link #getFile()}.toString().
	 *
	 * @return the file's path and name
	 */
	@Override
	public String toString() {
		return file.toString();
	}

	/**
	 * The file's name.
	 *
	 * @return the filename
	 */
	public String filename() {
		return file.getName();
	}

	public File getFile() {
		return file;
	}

	/**
	 * Opens the file and returns a {@code InputStream} object.
	 *
	 * @return the open file as {@code InputStream}
	 * @throws IOException thrown if the file could not be read
	 */
	public InputStream openInputStream() throws IOException {
		return new FileInputStream(file);
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) return true;
		if (o == null || getClass() != o.getClass()) return false;

		FileInformation that = (FileInformation) o;

		return file.equals(that.file);
	}

	@Override
	public int hashCode() {
		return file.hashCode();
	}

}


package js.container;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;

import js.lang.BugError;
import js.lang.InvocationException;
import js.log.Log;
import js.log.LogFactory;
import js.util.Classes;
import js.util.Strings;

/**
 * Built-in factory for local instances, local by contrast with remote or service instances. This instances factory deals with
 * {@link InstanceType#POJO} and {@link InstanceType#PROXY} managed classes. They are both created by invoking constructor with
 * provided arguments, that should be in the order and of types requested by constructor signature. There is no attempt to
 * discover constructor at runtime based on given arguments; this factory uses constructor provided by managed class, see
 * {@link ManagedClassSPI#getConstructor()}.
 *
 * @author Iulian Rotaru
 * @version final
 */
final class LocalInstanceFactory implements InstanceFactory {
	/** Class logger. */
	private static final Log log = LogFactory.getLog(LocalInstanceFactory.class);

	/**
	 * Local instances factory is built-in and does not have a type name.
	 *
	 * @throws UnsupportedOperationException this operation is not supported.
	 */
	@Override
	public InstanceType getInstanceType() {
		throw new UnsupportedOperationException();
	}

	/**
	 * Uses managed class constructor to create new instance with provided arguments. Arguments should be in order, types and
	 * number required by constructor signature.
	 *
	 * @param managedClass managed class,
	 * @param args optional arguments as required by constructor signature.
	 * @param <T> instance type;
	 * @return newly created managed instance.
	 * @throws IllegalArgumentException if args argument is not of types and number required by constructor.
	 * @throws InvocationException if constructor execution fails.
	 */
	@SuppressWarnings("unchecked")
	@Override
	public <T> T newInstance(ManagedClassSPI managedClass, Object... args) {
		Constructor<?> constructor = managedClass.getConstructor();
		if (constructor == null) {
			throw new BugError("Local instance factory cannot instantiate |%s|. Missing constructor.", managedClass);
		}

		Object instance = null;
		try {
			instance = constructor.newInstance(args);
		} catch (IllegalArgumentException e) {
			log.error("Wrong number of arguments or bad types for |%s|: [%s].", constructor, Strings.join(Classes.getParameterTypes(args)));
			throw e;
		} catch (InstantiationException e) {
			// managed class implementation is already validated, i.e. is not abstract and
			// test for existing constructor is performed... so no obvious reasons for instantiation exception
			throw new BugError(e);
		} catch (IllegalAccessException e) {
			// constructor has accessibility true and class is tested for public access modifier
			// so there is no reason for illegal access exception
			throw new BugError(e);
		} catch (InvocationTargetException e) {
			log.error("Managed instance constructor |%s| fail due to: %s.", constructor, e.getCause());
			throw new InvocationException(e);
		}

		if (managedClass.getInstanceType().equals(InstanceType.PROXY)) {
			// there are two proxy handlers: one transactional and one not
			// the difference is that transactional proxy handler gets a reference to an external transactional resource

			ManagedProxyHandler handler = null;
			if (managedClass.isTransactional()) {
				TransactionalResource transactionalResource = managedClass.getContainer().getInstance(TransactionalResource.class);
				handler = new ManagedProxyHandler(transactionalResource, managedClass, instance);
			} else {
				handler = new ManagedProxyHandler(managedClass, instance);
			}

			final ClassLoader classLoader = managedClass.getImplementationClass().getClassLoader();
			final Class<?>[] interfaceClasses = managedClass.getInterfaceClasses();
			return (T) Proxy.newProxyInstance(classLoader, interfaceClasses, handler);
		}

		return (T) instance;
	}
}


/**
 * Copyright (C) 2015 Michael Schnell. All rights reserved.
 * http://www.fuin.org/
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 3 of the License, or (at your option) any
 * later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library. If not, see http://www.gnu.org/licenses/.
 */
package org.fuin.srcgen4j.core.velocity;

import java.io.File;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;

import org.fuin.srcgen4j.commons.JaxbHelper;
import org.fuin.srcgen4j.commons.SrcGen4JConfig;
import org.fuin.srcgen4j.commons.SrcGen4JContext;
import org.fuin.srcgen4j.commons.UnmarshalObjectException;
import org.fuin.utils4j.Utils4J;

/**
 * Utility class for the {@link ParameterizedTemplateGenerator}.
 */
public final class PTGenHelper {

    private PTGenHelper() {
        // Never used
    }

    /**
     * Creates and initializes a SrcGen4J configuration from a configuration file that contains ONLY generators/parsers of type
     * {@link ParameterizedTemplateParser} and {@link ParameterizedTemplateGenerator}.
     *
     * @param context
     *            Current context - Cannot be NULL.
     * @param configFile
     *            XML configuration file to read - Cannot be NULL.
     *
     * @return New configuration instance.
     *
     * @throws UnmarshalObjectException
     *             Error reading the configuration.
     */
    public static SrcGen4JConfig createAndInit(final SrcGen4JContext context, final File configFile) throws UnmarshalObjectException {
        try {
            final JaxbHelper helper = new JaxbHelper();
            final SrcGen4JConfig config = helper.create(configFile, JAXBContext.newInstance(SrcGen4JConfig.class,
                    VelocityGeneratorConfig.class, ParameterizedTemplateParserConfig.class, ParameterizedTemplateGeneratorConfig.class));
            config.init(context, Utils4J.getCanonicalFile(configFile.getParentFile()));
            return config;
        } catch (final JAXBException ex) {
            throw new UnmarshalObjectException("Error reading the configuration: " + configFile, ex);
        }
    }

}


package net.typedrest;

import static java.util.Arrays.stream;
import static java.util.stream.Collectors.toList;
import org.apache.http.HttpResponse;

/**
 * Provides utility methods for HTTP headers.
 */
public final class HeaderUtils {

    private HeaderUtils() {
    }

    /**
     * Returns all Link headers listed in an {@link HttpResponse}.
     *
     * @param response The response to check for Link headers.
     * @return The Link headers found.
     */
    public static Iterable<LinkHeader> getLinkHeaders(HttpResponse response) {
        return stream(response.getHeaders("Link"))
                .flatMap(x -> stream(x.getElements()).map(LinkHeader::new))
                .collect(toList());
    }
}


package js.http.encoder;

import java.io.IOException;
import java.lang.reflect.Type;

import javax.servlet.http.HttpServletRequest;

import js.lang.SyntaxException;

/**
 * Reads invocation arguments from URL query parameters. This arguments reader implementation delegates
 * {@link QueryParametersParser} for URL parameters parsing.
 *
 * @author Iulian Rotaru
 * @version final
 */
final class FormUrlArgumentsReader implements ArgumentsReader {
	/**
	 * Reads invocation arguments from HTTP request URL parameters accordingly formal parameters list. This arguments reader
	 * implementation delegates {@link QueryParametersParser} for URL parameters parsing.
	 *
	 * @param httpRequest HTTP request,
	 * @param formalParameters formal parameters.
	 * @return arguments array.
	 * @throws IOException if reading from request input stream fails.
	 * @throws IllegalArgumentException if arguments from URL query parameters cannot be parsed.
	 */
	@Override
	public Object[] read(HttpServletRequest httpRequest, Type[] formalParameters) throws IOException, IllegalArgumentException {
		try {
			QueryParametersParser queryParameters = new QueryParametersParser(httpRequest.getInputStream());
			return queryParameters.getArguments(formalParameters);
		} catch (SyntaxException e) {
			throw new IllegalArgumentException(e);
		}
	}

	/** This method does nothing but is requested by interface. */
	@Override
	public void clean() {
	}
}


/*
 * Copyright (c) 2002 Cunningham & Cunningham, Inc.
 * Copyright (c) 2009-2015 by Jochen Wierum & Cologne Intelligence
 *
 * This file is part of FitGoodies.
 *
 * FitGoodies is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * FitGoodies is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with FitGoodies.  If not, see <http://www.gnu.org/licenses/>.
 */

package de.cologneintelligence.fitgoodies.runners;

import de.cologneintelligence.fitgoodies.Counts;
import de.cologneintelligence.fitgoodies.file.FileSystemDirectoryHelper;
import de.cologneintelligence.fitgoodies.util.FitUtils;

import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

/**
 * Implementation of FitResult which generates a indented HTML table.
 */
public final class FitResultTable implements FitResult {
	private final List<FileCount> results = new LinkedList<>();
	private final FileSystemDirectoryHelper dirHelper;

	/**
	 * Generates a new Object.
	 *
	 * @param helper helper object to convert pathnames
	 */
	public FitResultTable(final FileSystemDirectoryHelper helper) {
		dirHelper = helper;
	}

	/**
	 * Saves the result result of the file {@code file}.
	 *
	 * @param file   filename to identify the result
	 * @param result results
	 */
	@Override
	public void put(final File file, final Counts result) {
		FileCount fileCount = new FileCount(file, result);

		if (results.contains(fileCount)) {
			results.remove(fileCount);
		}

		results.add(fileCount);
	}

	/**
	 * Returns the {@code Counts} of a filename.
	 *
	 * @param file filename to look up
	 * @return {@code Counts} object which represents the file result
	 */
	public Counts get(final File file) {
		int index = results.indexOf(new FileCount(file, null));

		if (index == -1) {
			return null;
		} else {
			return results.get(index).getCounts();
		}
	}

	/**
	 * Returns all saved filenames.
	 *
	 * @return filenames of all results.
	 */
	public File[] getFiles() {
		List<File> result = new ArrayList<>();
		for (FileCount fileCount : results) {
			result.add(fileCount.getFile());
		}

		Collections.sort(result, new FitFileComparator());
		return result.toArray(new File[result.size()]);
	}

	/**
	 * Returns the sum of all results.
	 *
	 * @return sum of all results
	 */
	public Counts getSummary() {
		Counts result = new Counts();
		for (FileCount fileCount : results) {
			if (fileCount.getCounts() != null) {
				result.tally(fileCount.getCounts());
			}
		}
		return result;
	}

	private static String color(final Counts counts) {
		if (counts == null) {
			return FitUtils.HTML_GREY;
		} else if (counts.exceptions > 0 || counts.wrong > 0) {
			return FitUtils.HTML_RED;
		} else {
			return FitUtils.HTML_GREEN;
		}
	}

	/**
	 * Returns a single HTML Table row representing the results of the file
	 * {@code file}.
	 *
	 * @param file filename to look up
	 * @return HTML String with a a single Table row
	 */
	public String getRow(final File file) {
		StringBuilder builder = new StringBuilder();

		Counts counts = get(file);

		builder.append("
");

		int depth = dirHelper.dirDepth(file);
		indent(depth, builder);

		builder.append("");
		builder.append(file.getName());
		builder.append("");
		builder.append("	");

		if (counts == null) {
			builder.append("(none)");
		} else {
			builder.append(counts.toString());
		}
		builder.append("
");

		return builder.toString();
	}

	/**
	 * Returns a summary row for a whole test run.
	 *
	 * @param directory headline of the table
	 * @return a single HTML row
	 */
	public String getSummaryRow(final File directory) {
		StringBuilder builder = new StringBuilder();
		Counts counts = getSummary();

		builder.append("
");
		builder.append(directory.getName());
		builder.append("	");
		builder.append(counts.toString());
		builder.append("
");

		return builder.toString();
	}

	/**
	 * Prints out a table to {@code stream} which contains all saved
	 * results including all summary rows.
	 *
	 * @param directory headline of the table
	 * @param stream    stream to write results to
	 * @throws IOException thrown by {@code stream} in case of problems
	 */
	@Override
	public void print(final File directory, final OutputStream stream) throws IOException {
		OutputStreamWriter osw = new OutputStreamWriter(stream);
		BufferedWriter bw = new BufferedWriter(osw);

		bw.write("
");
		bw.write(getSummaryRow(directory));
		bw.write("

");

		File[] files = getFiles();
		if (files.length == 0) {
			bw.write("
no files found
");
		} else {
			File currentDir = directory;

			for (File file : files) {
				File newDir = file.getAbsoluteFile().getParentFile();
				if (!newDir.equals(currentDir) && !dirHelper.isSubDir(currentDir, newDir)) {
					for (File tmpDir : dirHelper.getParentDirs(dirHelper.getCommonDir(currentDir, file), newDir)) {
						bw.write(getSubSummaryRow(tmpDir));
					}
				}
				currentDir = newDir;

				bw.write(getRow(file));
			}
		}
		bw.write("
");

		bw.flush();
		osw.flush();
	}

	/**
	 * Generates a HTML summary row for a subdirectory.
	 *
	 * @param path subdirectory to process
	 * @return a single HTML row
	 * @throws IOException if path cannot be resolved correctly
	 */
	public String getSubSummaryRow(final File path) throws IOException {
		Counts sum = subDirSum(path);

		return String.format("
%s	%s
",
				color(sum), FitUtils.htmlSafeFile(dirHelper.abs2rel(new File("").getAbsolutePath(), path.getAbsolutePath())), sum.toString());
	}

	private Counts subDirSum(final File fullPath) throws IOException {
		Counts sum = new Counts();

		for (FileCount fileCount : results) {
			String filePath = fileCount.getFile().getCanonicalFile().getParentFile().getCanonicalFile().getAbsolutePath();
			if (filePath.startsWith(fullPath.getCanonicalFile().getAbsolutePath()) && fileCount.getCounts() != null) {
				sum.tally(fileCount.getCounts());
			}
		}

		return sum;
	}

	private void indent(final int depth, final StringBuilder builder) {
		for (int i = 0; i < depth; ++i) {
			builder.append("        ");
		}
	}
}


package js.http.encoder;

import java.io.IOException;
import java.io.OutputStreamWriter;

import javax.servlet.http.HttpServletResponse;

import js.json.Json;
import js.util.Classes;

/**
 * Return value serializer with JSON encoding. This return value writer delegates {@link Json#stringify(java.io.Writer, Object)}
 * for actual value serialization.
 *
 * @author Iulian Rotaru
 * @version final
 */
final class JsonValueWriter implements ValueWriter {
	/** JSON serializer delegated for return value encoding. */
	private final Json json;

	/** Create JSON value writer. */
	public JsonValueWriter() {
		json = Classes.loadService(Json.class);
	}

	/**
	 * Serialize return value to HTTP response using JSON encoding. This method delegates
	 * {@link Json#stringify(java.io.Writer, Object)} for value serialization.
	 *
	 * @param httpResponse HTTP response,
	 * @param value return value.
	 * @throws IOException if writing to HTTP response output stream fails.
	 */
	@Override
	public void write(HttpServletResponse httpResponse, Object value) throws IOException {
		json.stringify(new OutputStreamWriter(httpResponse.getOutputStream(), "UTF-8"), value);
	}
}


package js.core;

import js.lang.BugError;
import js.rmi.UnsupportedProtocolException;

/**
 * Server global master factory for managed instances. This utility class has JVM level visibility and just delegates requests
 * to {@link AppFactory}, application specific factory. All operations described by application factory interface are supported
 * by this master factory. See {@link AppFactory} class description for general presentation.
 * <p>
 * In order for master factory to be able to delegate application factory, it should be bound to current thread using
 * {@link #bind(AppFactory)}; otherwise {@link BugError} is thrown. One can test if application factory is properly bound using
 * {@link #isValid()}. Also there is convenient helper that retrieve current thread application factory.
 *
 * @author Iulian Rotaru
 * @version final
 */
public final class Factory {
	/**
	 * Inheritable thread local storage for application specific factories. This field keeps application factory reference on
	 * current thread; is updated by {@link #bind(AppFactory)} and value retrieved by {@link #getAppFactory()}. Uses inheritable
	 * thread local storage so that child threads can have access to parent application factory.
	 */
	private static ThreadLocal<AppFactory> tls = new InheritableThreadLocal<>();

	/** Forbid default constructor synthesis. */
	private Factory() {
	}

	/**
	 * Bind application specific factory to current thread. Depending on application architecture it can be done on application
	 * start or, in web contexts, on every new HTTP request. Given application specific factory is saved on current thread local
	 * storage.
	 *
	 * @param appFactory application specific factory.
	 */
	public static void bind(AppFactory appFactory) {
		// Important note: Servlet container uses a pool of threads so that a thread is used for execution of multiple requests,
		// but no sequence guaranteed. I do not know if threads pool is per web context or global per server. So, just to be
		// sure, do not try to cache and reuse stored thread local value, that is, every time call tls.get(); heretical behavior
		// may result if mix application factories.
		tls.set(appFactory);
	}

	/**
	 * Delegates {@link AppFactory#getInstance(Class, Object...)}.
	 *
	 * @param interfaceClass requested interface class,
	 * @param args optional constructor arguments.
	 * @param <T> managed class implementation.
	 * @return managed instance, created on the fly or reused from caches, but never null.
	 * @throws BugError if application factory is not bound to current thread.
	 * @see AppFactory#getInstance(Class, Object...)
	 */
	public static <T> T getInstance(Class<T> interfaceClass, Object... args) {
		return getAppFactory().getInstance(interfaceClass, args);
	}

	/**
	 * Delegates {@link AppFactory#getInstance(String, Class, Object...)}.
	 *
	 * @param instanceName instance name,
	 * @param interfaceClass requested interface class,
	 * @param args optional constructor arguments.
	 * @param <T> managed class implementation.
	 * @return managed instance, created on the fly or reused from caches, but never null.
	 * @throws BugError if application factory is not bound to current thread.
	 * @see AppFactory#getInstance(String, Class, Object...)
	 */
	public static <T> T getInstance(String instanceName, Class<T> interfaceClass, Object... args) {
		return getAppFactory().getInstance(instanceName, interfaceClass, args);
	}

	/**
	 * Delegates {@link AppFactory#getOptionalInstance(Class, Object...)}.
	 *
	 * @param interfaceClass requested interface class,
	 * @param args optional implementation constructor arguments.
	 * @return managed instance or null if no implementation found.
	 * @param <T> managed class implementation.
	 * @throws BugError if application factory is not bound to current thread.
	 * @see AppFactory#getOptionalInstance(Class, Object...)
	 */
	public static <T> T getOptionalInstance(Class<T> interfaceClass, Object... args) {
		return getAppFactory().getOptionalInstance(interfaceClass, args);
	}

	/**
	 * Delegates {@link AppFactory#getRemoteInstance(String, Class)}.
	 *
	 * @param implementationURL the URL of remote implementation,
	 * @param interfaceClass interface implemented by remote class.
	 * @param <T> managed class implementation.
	 * @return remote class proxy instance.
	 * @throws UnsupportedProtocolException if URL protocol is not supported.
	 * @throws BugError if application factory is not bound to current thread.
	 * @see AppFactory#getRemoteInstance(String, Class)
	 */
	public static <T> T getRemoteInstance(String implementationURL, Class<? super T> interfaceClass) {
		return getAppFactory().getRemoteInstance(implementationURL, interfaceClass);
	}

	/**
	 * Test if current thread has application specific factory bound. If return true current thread can safely be used for
	 * managed instances creation. Trying to create managed instances from a thread for which this predicate returns false will
	 * throw bug error.
	 *
	 * @return true if current thread has application specific factory bound.
	 */
	public static boolean isValid() {
		return tls.get() != null;
	}

	/**
	 * Helper method to retrieve application factory bound to current thread. Retrieve application factory from current thread
	 * local storage. In order to be successfully this method must be preceded by {@link #bind(AppFactory)} called from current
	 * thread; otherwise bug error is thrown.
	 *
	 * @return application factory bound to current thread.
	 * @throws BugError if current thread has no application factory bound.
	 */
	public static AppFactory getAppFactory() {
		AppFactory appFactory = tls.get();
		if (appFactory == null) {
			throw new BugError("No application factory bound to current thread |%s|. See #bind(AppFactory).", Thread.currentThread());
		}
		return appFactory;
	}
}


package net.typedrest.vaadin;

import com.vaadin.data.Container;
import com.vaadin.data.util.filter.SimpleStringFilter;
import com.vaadin.server.Sizeable;
import com.vaadin.ui.Grid;
import com.vaadin.ui.TextField;
import com.vaadin.ui.themes.ValoTheme;

/**
 * Utility methods for Vaadin {@link Grid}s.
 */
public final class GridUtils {

    private GridUtils() {
    }

    /**
     * Adds a row of filter text boxes to a Vaadin {@link Grid}.
     *
     * @param grid The grid to add the filter row to.
     */
    public static void addFilterRow(Grid grid) {
        if (grid.getHeaderRowCount() < 2) {
            grid.appendHeaderRow();
        }
        Grid.HeaderRow headerRow = grid.getHeaderRow(1);

        Container.Indexed container = grid.getContainerDataSource();
        container.getContainerPropertyIds().forEach(pid -> {
            TextField filterField = new TextField();
            filterField.setInputPrompt("Filter");
            filterField.addStyleName(ValoTheme.TEXTFIELD_SMALL);
            filterField.setWidth(100, Sizeable.Unit.PERCENTAGE);
            filterField.addTextChangeListener(event -> {
                ((Container.SimpleFilterable) container).removeContainerFilters(pid);
                if (!event.getText().isEmpty()) {
                    ((Container.Filterable) container).addContainerFilter(new SimpleStringFilter(pid, event.getText(), true, false));
                }
            });
            headerRow.getCell(pid).setComponent(filterField);
        });
    }
}


package js.container;

import js.lang.BugError;
import js.lang.NoProviderException;
import js.util.Classes;

/**
 * Built-in factory for service instances. This instances factory deals with {@link InstanceType#SERVICE} managed classes. It
 * uses managed class interface to locate service and load it. Throws {@link NoProviderException} if no service implementation
 * found on run-time.
 *
 * @author Iulian Rotaru
 * @version final
 */
final class ServiceInstanceFactory implements InstanceFactory {
	/**
	 * Service instances factory is built-in and does not have a type name.
	 *
	 * @throws UnsupportedOperationException this operation is not supported.
	 */
	@Override
	public InstanceType getInstanceType() {
		throw new UnsupportedOperationException();
	}

	/**
	 * Load service defined by managed class interface and return service instance. This factory does not support arguments.
	 * Service provider should be present into run-time otherwise no provider exception is thrown.
	 *
	 * @param managedClass managed class,
	 * @param args service instances factory does not support arguments.
	 * @return loaded service instance.
	 * @throws IllegalArgumentException if args argument is not empty.
	 * @throws NoProviderException if no service provider found on run-time for requested interface.
	 */
	@SuppressWarnings("unchecked")
	@Override
	public  I newInstance(ManagedClassSPI managedClass, Object... args) {
		if (args.length > 0) {
			throw new IllegalArgumentException("Service instances factory does not support arguments.");
		}
		Class<?>[] interfaceClasses = managedClass.getInterfaceClasses();
		if (interfaceClasses == null) {
			throw new BugError("Invalid managed class. Null interface classes.");
		}
		if (interfaceClasses.length != 1) {
			throw new BugError("Invalid managed class. It should have exactly one interface class.");
		}
		return (I) Classes.loadService(interfaceClasses[0]);
	}
}


/**
 * Copyright (C) 2015 Michael Schnell. All rights reserved.
 * http://www.fuin.org/
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 3 of the License, or (at your option) any
 * later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library. If not, see http://www.gnu.org/licenses/.
 */
package org.fuin.srcgen4j.core.xtext;

import static org.fuin.utils4j.Utils4J.replaceVars;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.stream.Collectors;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;

import org.eclipse.emf.common.util.URI;
import org.fuin.srcgen4j.commons.Config;
import org.fuin.srcgen4j.commons.InitializableElement;
import org.fuin.srcgen4j.commons.ParserConfig;
import org.fuin.srcgen4j.commons.SrcGen4JContext;
import org.fuin.utils4j.Utils4J;
import org.fuin.xmlcfg4j.AbstractElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Configuration for a {@link XtextParser}.
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "xtext-parser-config")
public class XtextParserConfig extends AbstractElement implements InitializableElement<XtextParserConfig, Config<ParserConfig>> {

    private static final Logger LOG = LoggerFactory.getLogger(XtextParserConfig.class);

    @XmlAttribute(name = "modelPath")
    private String modelPath;

    @XmlAttribute(name = "modelExt")
    private String modelExt;

    @XmlAttribute(name = "setupClass")
    private String setupClassName;

    private transient SrcGen4JContext context;

    private transient List<File> modelDirs;

    private transient List<URI> modelResources;

    private transient Class<?> setupClass;

    /**
     * Default constructor.
     */
    public XtextParserConfig() {
        super();
    }

    /**
     * Constructor with model path.
     *
     * @param modelPath
     *            Model path.
     * @param modelExt
     *            Model file extension.
     */
    public XtextParserConfig(final String modelPath, final String modelExt) {
        super();
        this.modelPath = modelPath;
        this.modelExt = modelExt;
    }

    /**
     * Returns the model path.
     *
     * @return Model path.
     */
    public final String getModelPath() {
        return modelPath;
    }

    /**
     * Sets the model path to a new value.
     *
     * @param modelPath
     *            Model path to set.
     */
    public final void setModelPath(final String modelPath) {
        this.modelPath = modelPath;
    }

    /**
     * Returns the Model file extension.
     *
     * @return Model file extension.
     */
    public final String getModelExt() {
        return modelExt;
    }

    /**
     * Sets the Model file extension.
     *
     * @param modelExt
     *            Model file extension.
     */
    public final void setModelExt(final String modelExt) {
        this.modelExt = modelExt;
    }

    /**
     * Returns the setup class name.
     *
     * @return Full qualified name of the class that does the DSL setup.
     */
    public final String getSetupClassName() {
        return setupClassName;
    }

    /**
     * Sets the setup class name to a new value.
     *
     * @param setupClassName
     *            Full qualified name of the class that does the DSL setup.
     */
    public final void setSetupClassName(final String setupClassName) {
        this.setupClassName = setupClassName;
    }

    @Override
    public final XtextParserConfig init(final SrcGen4JContext context, final Config<ParserConfig> parent, final Map<String, String> vars) {
        this.context = context;
        inheritVariables(vars);
        setModelPath(replaceVars(getModelPath(), getVarMap()));
        return this;
    }

    /**
     * Returns the setup class.
     *
     * @return Setup class of type {@link #setupClassName}.
     */
    public final Class<?> getSetupClass() {
        if (setupClass != null) {
            return setupClass;
        }
        LOG.info("Creating setup class: {}", setupClassName);
        try {
            setupClass = Class.forName(setupClassName, true, context.getClassLoader());
        } catch (final ClassNotFoundException ex) {
            throw new RuntimeException("Couldn't load setup class: " + setupClassName, ex);
        }
        return setupClass;
    }

    private List<String> paths() {
        final List<String> list = new ArrayList<>();
        final StringTokenizer tok = new StringTokenizer(modelPath, ";");
        while (tok.hasMoreTokens()) {
            list.add(tok.nextToken());
        }
        return list;
    }

    /**
     * Returns the information if the given string is a file reference. It's considered a file if there has no ':' character in the text.
     *
     * @param str
     *            Text to test for a file.
     *
     * @return {@code true} if it references a file.
     */
    public static boolean isFile(final String str) {
        if (str.contains(":")) {
            return false;
        }
        return true;
    }

    /**
     * Returns a file for the string.
     *
     * @param str
     *            File reference.
     *
     * @return File.
     */
    public static File asFile(final String str) {
        return Utils4J.getCanonicalFile(new File(str));
    }

    /**
     * Returns the information if the given string is a resource reference. It's considered a file if there is a ':' character in the text.
     *
     * @param str
     *            Text to test for a resource.
     *
     * @return {@code true} if it references a resource.
     */
    public static boolean isResource(final String str) {
        return !isFile(str);
    }

    /**
     * Returns a file for the string.
     *
     * @param str
     *            File reference.
     *
     * @return File.
     */
    public static URI asResource(final String str) {
        return URI.createURI(str);
    }

    /**
     * Returns a list of model directories to parse.
     *
     * @return Directory list or NULL.
     */
    public final List<File> getModelDirs() {
        if ((modelDirs == null) && (modelPath != null)) {
            modelDirs = paths().stream().filter(XtextParserConfig::isFile).map(XtextParserConfig::asFile).collect(Collectors.toList());
        }
        return modelDirs;
    }

    /**
     * Returns a list of model resources to parse.
     *
     * @return List of resources or NULL.
     */
    public final List<URI> getModelResources() {
        if ((modelResources == null) && (modelPath != null)) {
            modelResources = new ArrayList<>();
            modelResources = paths().stream().filter(XtextParserConfig::isResource).map(XtextParserConfig::asResource)
                    .collect(Collectors.toList());
        }
        return modelResources;
    }

}


/*
 * Copyright (c) 2002 Cunningham & Cunningham, Inc.
 * Copyright (c) 2009-2015 by Jochen Wierum & Cologne Intelligence
 *
 * This file is part of FitGoodies.
 *
 * FitGoodies is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * FitGoodies is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with FitGoodies.  If not, see <http://www.gnu.org/licenses/>.
 */

package de.cologneintelligence.fitgoodies.alias;

import de.cologneintelligence.fitgoodies.Fixture;
import de.cologneintelligence.fitgoodies.htmlparser.FitRow;
import de.cologneintelligence.fitgoodies.util.DependencyManager;

/**
 * Fixture to register aliases at runtime.
 */
public class SetupFixture extends Fixture {
	/**
	 * alias name to use.
	 */
	public String alias;

	/**
	 * class name to use.
	 */
	public String className;

	/**
	 * Reads a row which contains two cells and registers an alias.
	 *

	 * The first cell must contain the alias, the second one must contains the
	 * fully qualified class name. Using another alias as class name is not
	 * permitted.
	 *

	 * Cross references are resolved.
	 *
	 * @param row row to parse
	 */
	@Override
	protected void doRow(FitRow row) {
        if (row.size() < 2) {
            row.cells().get(0).ignore();
            return;
        }

		alias = validator.preProcess(row.cells().get(0));
		className = validator.preProcess(row.cells().get(1));

		AliasHelper aliasHelper = DependencyManager.getOrCreate(AliasHelper.class);
		aliasHelper.register(alias, className);
	}
}


package net.typedrest.vaadin.forms;

import com.vaadin.data.Container.Filter;
import com.vaadin.data.Item;
import com.vaadin.data.util.BeanItemContainer;
import com.vaadin.ui.*;
import com.vaadin.ui.themes.ValoTheme;
import java.util.Collection;
import java.util.Set;

/**
 * UI component for picking a subset of entities from a set of candidates.
 *
 * Wraps a {@link TwinColSelect} handling the creation of a
 * {@link BeanItemContainer} and adding incremental search.
 *
 * @param <T> The type of entities the picker offers.
 */
public class EntityPicker<T> extends CustomField<Set<T>> {

    private final Class<T> entityType;
    private final TextField filterField = new TextField();
    private final TwinColSelect twinColSelect = new TwinColSelect();
    private BeanItemContainer<T> container;

    /**
     * Creates a new entity picker.
     *
     * @param type The type of entities the picker offers.
     */
    public EntityPicker(Class<T> type) {
        this.entityType = type;
    }

    @Override
    protected Component initContent() {
        filterField.addTextChangeListener(event -> {
            if (container == null) {
                return;
            }

            container.removeAllContainerFilters();
            container.addContainerFilter(new Filter() {
                @Override
                public boolean passesFilter(Object itemId, Item item) throws UnsupportedOperationException {
                    return itemId.toString().toLowerCase().contains(event.getText().toLowerCase())
                            || ((Collection) twinColSelect.getValue()).contains(itemId);
                }

                @Override
                public boolean appliesToProperty(Object propertyId) {
                    return true;
                }
            });
        });
        filterField.setInputPrompt("Filter");
        filterField.addStyleName(ValoTheme.TEXTFIELD_SMALL);
        filterField.setWidth(50, Unit.PERCENTAGE);

        twinColSelect.setLeftColumnCaption("Available");
        twinColSelect.setSizeFull();
        twinColSelect.setRightColumnCaption("Selected");
        twinColSelect.setNullSelectionAllowed(true);

        VerticalLayout layout = new VerticalLayout(filterField, twinColSelect);
        layout.setSizeFull();
        return layout;
    }

    @Override
    public Class<? extends Set<T>> getType() {
        return (Class<Set<T>>) ((Class) Set.class);
    }

    @Override
    protected void setInternalValue(Set<T> newValue) {
        twinColSelect.setValue(newValue);
        super.setInternalValue(newValue);
    }

    @Override
    protected Set<T> getInternalValue() {
        return (Set<T>) twinColSelect.getValue();
    }

    /**
     * Sets a set of candidates for selection.
     *
     * @param candidates The candidates for selection.
     */
    public void setCandidates(Collection<T> candidates) {
        twinColSelect.setContainerDataSource(
                container = new BeanItemContainer<>(entityType, candidates));
    }
}


/*
 * Copyright (c) 2002 Cunningham & Cunningham, Inc.
 * Copyright (c) 2009-2015 by Jochen Wierum & Cologne Intelligence
 *
 * This file is part of FitGoodies.
 *
 * FitGoodies is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * FitGoodies is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with FitGoodies.  If not, see <http://www.gnu.org/licenses/>.
*/

package de.cologneintelligence.fitgoodies.runners;

import de.cologneintelligence.fitgoodies.ActionFixture;
import de.cologneintelligence.fitgoodies.Counts;
import de.cologneintelligence.fitgoodies.file.FileInformation;
import de.cologneintelligence.fitgoodies.file.FileSystemDirectoryHelper;
import de.cologneintelligence.fitgoodies.htmlparser.FitCell;
import de.cologneintelligence.fitgoodies.htmlparser.FitRow;
import de.cologneintelligence.fitgoodies.util.DependencyManager;

import java.io.File;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;

/**
 * Run sub-fixtures.
 *

 * This fixture allows to start other fixtures and collects their results.
 * The files must be specified relative to the fixtures file path.
 *

 * Example:
 *

fitgoodies.runners.RunFixture

 *
file	file1.html

 *
file	dir/file2.html

 *
directory	other_tests/

 *

 */
public class RunFixture extends ActionFixture {
    private Runner runner;
    private FileSystemDirectoryHelper dirHelper;
    private File thisDir;
    private File outDir;

    @Override
    public void setUp() throws Exception {
        super.setUp();

        RunnerHelper helper = DependencyManager.getOrCreate(RunnerHelper.class);
        dirHelper = helper.getHelper();
        thisDir = helper.getFile().getParentFile();
        outDir = helper.getResultFile().getParentFile();
        runner = helper.getRunner();
    }

    @Override
    protected void doRows(final List<FitRow> rows) throws Exception {
        // since rows are inserted, we need a constant copy of the "real" content
        for (FitRow row : new ArrayList<>(rows)) {
            super.doRow(row);
        }
    }

    /**
     * Calls {@link #file(String)}, using the next cell as its parameter.
     *
     * @throws Exception propagated to fit
     */
    public void file() throws Exception {
        transformAndEnter();
    }

    /**
     * Calls {@link #directory(String)}, using the next cell as its parameter.
     *
     * @throws Exception propagated to fit
     */
    public void directory() throws Exception {
        transformAndEnter();
    }

    private void appendResults(
        final FitRow row,
        final String name,
        final Counts results)
        throws ParseException {

        FitCell cell = row.cells().get(2);
        cell.setDisplayValueRaw("" + name + "");

        cell = row.append();
        cell.setDisplayValue(results.toString());
    }

    /**
     * Runs the file {@code fileName} using the current runner and replaces
     * the current row with the results.
     *
     * @param fileName file to process
     * @throws Exception propagated to fit
     */
    public void file(final String fileName) throws Exception {
        String in = thisDir.getAbsolutePath();
        File out = outDir.getAbsoluteFile();

        //noinspection ResultOfMethodCallIgnored
        out.mkdirs();

        File inputFile = dirHelper.rel2abs(in, fileName);
        File outputFile = dirHelper.subdir(out, inputFile.getName());
        Counts result = runner.run(inputFile, outputFile);

        appendResults(row, inputFile.getName(), result);
        row.getTable().getCounts().tally(result);
    }

    /**
     * Runs all HTML files in {@code dir} using the current runner and replaces
     * the current row with the results.
     *
     * @param dir file to process
     * @throws Exception propagated to fit
     */
    // TODO: not tested?
    public void directory(final String dir) throws Exception {
        File srcDir = dirHelper.rel2abs(thisDir.getAbsolutePath(), dir);

        List<FileInformation> files = new DirectoryFilter(srcDir, dirHelper).getSelectedFiles();

        RunConfiguration runConfiguration = new RunConfiguration();
        runConfiguration.setEncoding(runner.getEncoding());
        runConfiguration.setBaseDir(srcDir);
        runConfiguration.setDestination(outDir.getPath());
        runConfiguration.setSource(files.toArray(new FileInformation[files.size()]));
        System.out.println("Run: " + files + " in " + srcDir + " to " + outDir);

        final FitRunner fitRunner = new FitRunner(dirHelper, runConfiguration);

        FitParseResult results = new FitParseResult();
        fitRunner.run(results);
        results.insertAndReplace(row);
        row.getTable().getCounts().tally(results.getCounts());
    }
}


package js.servlet;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Properties;
import java.util.Stack;

import javax.servlet.ServletContext;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import js.container.Container;
import js.lang.Config;
import js.lang.ConfigBuilder;
import js.lang.ConfigException;
import js.log.Log;
import js.log.LogFactory;
import js.util.Classes;
import js.util.Strings;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

/**
 * Builder for configuration object used to configure tiny container. Create tiny container configuration object and load it
 * from external library and application descriptors. By convention configuration object has the same name as the web
 * application that creates the container. See {@link Container} for container descriptor description.
 *
 * @author Iulian Rotaru
 * @version final
 */
public class TinyConfigBuilder extends ConfigBuilder {
	/** Class logger. */
	private static final Log log = LogFactory.getLog(TinyConfigBuilder.class);

	/** Name for application deployed on ROOT context. */
	private static final String ROOT_APP_NAME = "ROOT";

	/**
	 * Configuration object for tiny container loaded from library and application descriptors. This is the root of
	 * configuration objects tree and is passed to loader to actually populate it from XML streams.
	 */
	private Config config;

	/**
	 * Test constructor creates and empty configuration object with given name.
	 *
	 * @param configName configuration object name.
	 */
	protected TinyConfigBuilder(String configName) {
		config = new Config(configName);
	}

	/**
	 * Construct application configuration instance with information from given servlet context.
	 *
	 * @param context Servlet context bound to application,
	 * @param properties context properties defining variables to inject on descriptors.
	 * @throws ConfigException if application descriptor is not well formed or invalid.
	 */
	public TinyConfigBuilder(ServletContext context, Properties properties) throws ConfigException {
		config = new Config(getAppName(context.getContextPath()));

		File contextDir = new File(context.getRealPath(""));
		File webinfDir = new File(contextDir, "WEB-INF");

		Loader loader = new Loader(config, properties);

		// first load library descriptor
		loadXML(Classes.getResourceAsStream("lib-descriptor.xml"), loader);

		// load application specific configuration document(s)
		File file = new File(webinfDir, "app.xml");
		try {
			loadXML(new FileInputStream(file), loader);
		} catch (FileNotFoundException e) {
			log.debug("Application |%s| has no descriptor. No application specific configuration.", config.getName());
			new ConfigException(e);
		}
	}

	/**
	 * Return configuration object. This method, on current implementation, is just a getter. Configuration object loading is
	 * performed by constructor.
	 *
	 * @return tiny container configuration object.
	 */
	@Override
	public Config build() {
		return config;
	}

	// --------------------------------------------------------------------------------------------
	// UTILITY METHODS

	/**
	 * Get application name from servlet context path. Context path is used to identify web application within request URI.
	 * Application name is context path without leading path separator and with normalized root name. Normalized root name uses
	 * {@link #ROOT_APP_NAME} when context path is empty.
	 *
	 * @param contextPath servlet context path with leading path separator.
	 * @return application name, never null.
	 */
	private static String getAppName(String contextPath) {
		// as result from api-doc context path always start with '/' and is empty for root context
		return contextPath.isEmpty() ? ROOT_APP_NAME : contextPath.substring(1);
	}

	/**
	 * Load configuration document from file.
	 *
	 * @param inputStream configuration XML file,
	 * @param loader SAX handler in charge of configuration loading.
	 * @throws ConfigException if XML document loading fails.
	 */
	protected static void loadXML(InputStream inputStream, Loader loader) throws ConfigException {
		try {
			SAXParserFactory factory = SAXParserFactory.newInstance();
			SAXParser parser = factory.newSAXParser();
			XMLReader reader = parser.getXMLReader();
			reader.setContentHandler(loader);
			reader.parse(new InputSource(inputStream));
		} catch (Exception e) {
			throw new ConfigException("Fail to load configuration document from file |%s|: %s", inputStream, e);
		}
	}

	// --------------------------------------------------------------------------------------------
	// INNER CLASSES

	/**
	 * Parse XML stream and update configuration objects tree with the given root.
	 *
	 * @author Iulian Rotaru
	 * @version final
	 */
	public static class Loader extends DefaultHandler {
		/** Tag name for property element. */
		private static final String TAG_PROPERTY = "property";

		/**
		 * Stack of parent configuration objects updated at opening tags, respective closing tags. The top of this stack always
		 * contain current parent configuration object.
		 */
		private final Stack<Config> parentsStack = new Stack<>();

		/** Optional properties, default to empty, for variables resolving. */
		private final Properties properties;

		/** Nesting level. */
		private int nestingLevel;

		/**
		 * Construct loader with given root configuration object.
		 *
		 * @param config root configuration object.
		 */
		public Loader(Config config) {
			this(config, new Properties());
		}

		/**
		 * Construct loader with given root configuration object and properties used to resolve variables.
		 *
		 * @param config root configuration object,
		 * @param properties properties used to resolve variables.
		 */
		public Loader(Config config, Properties properties) {
			this.parentsStack.push(config);
			this.properties = properties;
		}

		/**
		 * Create configuration objects with name based on given qualified name and insert into configuration objects tree. Also
		 * updates nesting level and configuration objects stack.
		 *
		 * @param uri name space URI, unused by current implementation,
		 * @param localName local name relative to name space, unused by current implementation,
		 * @param qName element qualified name,
		 * @param attributes element attributes.
		 * @throws SAXException if a required attribute or variable is missing or not with bad syntax.
		 */
		@Override
		public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
			if (nestingLevel == 0) {
				++nestingLevel;
				return;
			}

			if (TAG_PROPERTY.equals(qName)) {
				Config config = parentsStack.peek();
				config.setProperty(value(attributes, "name"), value(attributes, "value"));
			} else {
				Config config = new Config(qName);
				Config parent = parentsStack.peek();
				parent.addChild(config);
				parentsStack.push(config);

				for (int i = 0; i < attributes.getLength(); ++i) {
					final String name = attributes.getQName(i);
					config.setAttribute(name, value(attributes, name));
				}
			}

			++nestingLevel;
		}

		/**
		 * Decrease nesting level and remove elements stack top.
		 *
		 * @param uri name space URI, unused by current implementation,
		 * @param localName local name relative to name space, unused by current implementation,
		 * @param qName element qualified name.
		 */
		@Override
		public void endElement(String uri, String localName, String qName) {
			--nestingLevel;
			if (!TAG_PROPERTY.equals(qName) && nestingLevel > 0) {
				parentsStack.pop();
			}
		}

		// ----------------------------------------------------------------------------------------
		// UTILITY METHODS

		/**
		 * Get attribute value resolving variable, if any. Return attribute value, never null. Throws exception if there is no
		 * attribute with requested name.
		 *

		 * If attribute value denotes a variable resolve it from this loader {@link #properties} or system properties, in this
		 * order. Variable syntax is standard dollar notation, e.g. ${variable.name}. Is good practice to use
		 * qualified names for variables.
		 *

		 * Is legal for a variable to not be resolved in which case returned value is variable name itself, that is, attribute
		 * value as it is.
		 *
		 * @param attributes attributes list,
		 * @param attributeName attribute name to load value for.
		 * @return variable value, never null.
		 * @throws SAXException if there is no attribute with requested name or variable with bad syntax.
		 */
		private String value(Attributes attributes, String attributeName) throws SAXException {
			String value = attributes.getValue(attributeName);
			if (value == null) {
				throw new SAXException(new ConfigException("Missing attribute |%s|.", attributeName));
			}

			String variableName = getVariableName(value);
			if (variableName == null) {
				return value;
			}
			String variableValue = properties.getProperty(variableName);
			if (variableValue == null) {
				variableValue = System.getProperty(variableName);
			}
			if (variableValue == null) {
				log.debug("Missing variable |%s|.", variableName);
				return value;
			}
			return value.replace(Strings.concat("${", variableName, '}'), variableValue);
		}

		/**
		 * Get variable name from string value or null if value does not contain a variable. Variable uses standard dollar
		 * syntax, that is, ${variable.name}. This method returns variable name. If given string value is not a
		 * variable returns null.
		 *
		 * @param value string value, not null.
		 * @return variable name or null is none found.
		 * @throws SAXException if variable name syntax is wrong.
		 * @throws NullPointerException if value argument is null.
		 */
		private static String getVariableName(String value) throws SAXException {
			int variableStartIndex = value.indexOf("${");
			if (variableStartIndex == -1) {
				return null;
			}
			int variableEndIndex = value.indexOf('}', variableStartIndex);
			if (variableEndIndex == -1) {
				throw new SAXException(String.format("Bad variable value |%s|. Missing closing mark.", value));
			}
			return value.substring(variableStartIndex + 2, variableEndIndex);
		}
	}
}


package net.typedrest.vaadin.views;

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import net.typedrest.Endpoint;
import net.typedrest.vaadin.events.EndpointEvent;
import com.vaadin.ui.*;
import java.io.*;
import lombok.Getter;
import lombok.Setter;
import org.apache.http.*;

/**
 * Base class for building view components operating on an {@link Endpoint}.
 *
 * @param <TEndpoint> The specific type of {@link Endpoint} to operate on.
 */
public abstract class AbstractEndpointView<TEndpoint extends Endpoint>
        extends ViewComponent {

    /**
     * The REST endpoint this component operates on.
     */
    protected final TEndpoint endpoint;

    /**
     * Creates a new REST endpoint component.
     *
     * @param endpoint The REST endpoint this component operates on.
     * @param eventBus Used to send event between components.
     */
    protected AbstractEndpointView(TEndpoint endpoint, EventBus eventBus) {
        super(eventBus);
        this.endpoint = endpoint;
        setSizeFull();
    }

    @Override
    public void attach() {
        super.attach();
        refresh();
    }

    /**
     * Reloads data from the endpoint.
     */
    public void refresh() {
        try {
            onLoad();
        } catch (IOException | IllegalArgumentException | IllegalAccessException | IllegalStateException ex) {
            onError(ex);
        }
    }

    /**
     * Handler for loading data for the endpoint.
     *
     * @throws IOException Network communication failed.
     * @throws IllegalArgumentException {@link HttpStatus#SC_BAD_REQUEST}
     * @throws IllegalAccessException {@link HttpStatus#SC_UNAUTHORIZED} or
     * {@link HttpStatus#SC_FORBIDDEN}
     * @throws FileNotFoundException {@link HttpStatus#SC_NOT_FOUND} or
     * {@link HttpStatus#SC_GONE}
     * @throws IllegalStateException {@link HttpStatus#SC_CONFLICT}
     * @throws RuntimeException Other non-success status code.
     */
    protected void onLoad()
            throws IOException, IllegalArgumentException, IllegalAccessException, FileNotFoundException, IllegalStateException {
    }

    /**
     * Handler for errors reported by REST endpoints.
     *
     * @param ex The exception reported by the REST endpoint.
     */
    protected void onError(Exception ex) {
        Notification.show("Error", ex.getLocalizedMessage(), Notification.Type.ERROR_MESSAGE);
    }

    /**
     * The Link relation type used by the server to send refresh notifications.
     */
    @Getter
    @Setter
    private String notifyRel = "notify";

    @Subscribe
    public void handle(EndpointEvent<?> message) {
        if (message.getEndpoint().getLinks(notifyRel).contains(endpoint.getUri())) {
            refresh();
        }
    }
}


package net.typedrest.vaadin.forms;

import static net.typedrest.BeanUtils.*;
import net.typedrest.*;
import com.vaadin.shared.ui.datefield.Resolution;
import static com.vaadin.shared.util.SharedUtil.propertyIdToHumanFriendly;
import com.vaadin.ui.*;
import com.vaadin.ui.themes.ValoTheme;
import java.beans.*;

/**
 * An entity form that uses auto-generated fields.
 *
 * @param <TEntity> The type of entity the form operates on.
 */
public class AutoEntityForm<TEntity>
        extends AbstractEntityForm<TEntity> {

    /**
     * Creates a new entity form.
     *
     * @param entityType The type of entity the form operates on.
     */
    public AutoEntityForm(Class<TEntity> entityType) {
        super(entityType);
        setCompositionRoot(buildAndBind(entityType));
    }

    /**
     * Builds a form layout with fields for all properties exposed by the
     * entity.
     *
     * @param entityType The type of entity to build a form for.
     * @return The form layout.
     */
    protected Component buildAndBind(Class<TEntity> entityType) {
        FormLayout layout = new FormLayout();

        getPropertiesWithoutAnnotation(entityType, EditorHidden.class).forEach((property) -> {
            if (property.getWriteMethod() == null) {
                return;
            }

            Component component = buildAndBind(property);
            component.setWidth(100, Unit.PERCENTAGE);
            if (component.getCaption() == null) {
                component.setCaption(propertyIdToHumanFriendly(property.getName()));
            }
            if (component instanceof DateField) {
                ((DateField) component).setResolution(Resolution.SECOND);
            }
            layout.addComponent(component);

            getAnnotation(entityType, property, Description.class)
                    .ifPresent(x -> layout.addComponent(buildDescriptionComponent(property, x.value())));
        });

        return layout;
    }

    /**
     * Builds a field component (label + input) for a specific property and sets
     * up its data binding.
     *
     * @param property The property to create the field for.
     * @return The newly created component.
     */
    protected Component buildAndBind(PropertyDescriptor property) {
        if (BeanUtils.getAnnotation(entityType, property, MultiLine.class).isPresent()) {
            TextArea textArea = new TextArea();
            fieldGroup.bind(textArea, property.getName());
            return textArea;
        } else {
            return fieldGroup.buildAndBind(property.getName());
        }
    }

    /**
     * Builds a description component (label) for a specific property.
     *
     * @param property The property to create the component for.
     * @param description The description text to show.
     * @return The newly created component.
     */
    protected Component buildDescriptionComponent(PropertyDescriptor property, String description) {
        Label label = new Label(description);
        label.addStyleName(ValoTheme.LABEL_LIGHT);
        label.addStyleName(ValoTheme.LABEL_SMALL);
        return label;
    }
}


package js.http.encoder;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import js.converter.Converter;
import js.converter.ConverterException;
import js.converter.ConverterRegistry;
import js.lang.BugError;
import js.lang.SyntaxException;
import js.log.Log;
import js.log.LogFactory;
import js.util.Classes;
import js.util.Strings;
import js.util.Types;

/**
 * Parse parameters encoded into URL query string format. This parser can be used for both URL query string from HTTP request
 * and form content encoded application/x-www-form-urlencoded. There are specialized constructors for both cases:
 * {@link QueryParametersParser#QueryParametersParser(String)}, respective
 * {@link QueryParametersParser#QueryParametersParser(InputStream)}. The actual parser is implemented by {@link #parse(Reader)}
 * that returns a list of decoded parameters. Constructors merely store parsed parameters into {@link #parameters} field.
 *

 * After construction internal parameters list is initialized. Next step is to get method invocation arguments from decoded
 * parameters.
 *
 *

 * QueryParameters queryParameters = new QueryParameters(httpRequest);
 * Type[] formalParameters = new Type[] { String.class, String.class, String.class };
 * Object[] arguments = queryParameters.getArguments(formalParameters);
 *

 *
 * Method {@link #getArguments(Type[])} takes formal parameters types and returns invocation arguments mapped by position. Note
 * that mapping by name is not possible since Java does not preserve parameter names on run-time. This forces caller to ensure
 * given formal parameters are in the same order as decoded parameters. This class uses {@link #asObject(String, Type)} helper
 * method to actually create argument values of proper type, accordingly requested formal parameter types.
 *

 * It is legal for a parameter value to be missing so next construct is acceptable:
 * name1=value&name2=&name3=value3 . Anyway, even if value is missing, name/value separator (=) should be
 * present. When value is missing parameter is initialized with an empty value accordingly formal parameter type, see
 * {@link Types#getEmptyValue(Type)}.
 *

 * This parser supports an extension to query string syntax. If there is a single parameter it is legal to have only value,
 * without name and separator. This value is said to be a raw value. For example, instead of using URL like
 * .../captha/image?token=1234 is possbile to use .../captha/image?1234.
 *

 * Query parameters implementation is thread safe; it has all fields final and parser is implemented functional.
 *
 * @author Iulian Rotaru
 * @version final
 */
final class QueryParametersParser {
	/** Class logger. */
	private static final Log log = LogFactory.getLog(QueryParametersParser.class);

	/** Reusable empty reader for null query string. */
	private static final Reader EMPTY_READER = new Reader() {
		@Override
		public int read(char[] cbuf, int off, int len) throws IOException {
			return -1;
		}

		@Override
		public void close() throws IOException {
			throw new UnsupportedOperationException();
		}
	};

	/** Parsed parameters list. */
	private final List<Parameter> parameters;

	/**
	 * Construct query parameters for URL query string from HTTP request. This constructor creates a reader for given query
	 * string and delegates the {@link #parse(Reader)}. Trailing question mark (?) is ignored. If query string is null resulting
	 * parameters list is empty.
	 *
	 * @param queryString source query string, null accepted.
	 * @throws IOException for the very unlikely fail to read request query string.
	 * @throws UnsupportedEncodingException if request query string encoding is not UTF-8.
	 * @throws SyntaxException if query string format is invalid.
	 */
	public QueryParametersParser(String queryString) throws IOException {
		Reader reader = null;

		if (queryString == null) {
			reader = EMPTY_READER;
		} else {
			// from API is not very clear if query string has leading separator so decide to play safe
			if (queryString.charAt(0) == '?') {
				queryString = queryString.substring(1);
			}
			reader = new StringReader(queryString);
		}

		this.parameters = parse(reader);
	}

	/**
	 * Construct query parameters for input stream, usually form content encoded application/x-www-form-urlencoded.
	 * This constructor just convert input stream to reader and delegates the {@link #parse(Reader)}.
	 *
	 * @param inputStream source input stream carrying URL encoded parameters.
	 * @throws IOException if stream read operations fail.
	 * @throws UnsupportedEncodingException if URL encoded parameters encoding is not UTF-8.
	 * @throws SyntaxException if URL encoded parameters are not properly encoded.
	 */
	public QueryParametersParser(InputStream inputStream) throws IOException {
		this.parameters = parse(new InputStreamReader(inputStream, "UTF-8"));
	}

	/**
	 * Parse URL query parameters provided by source reader. Detect query parameters name and and value and update a list of
	 * parsed parameters. Takes care to decode escaped characters from both parameter names and values.
	 *

	 * This parser expect UTF-8 for text encoding and throws unsupported encoding for different codes.
	 *
	 * @param reader source reader.
	 * @return list of parsed parameters.
	 * @throws IOException if read operation fails.
	 * @throws UnsupportedEncodingException if URL encoded parameters encoding is not UTF-8.
	 * @throws SyntaxException if URL query parameters are not properly encoded.
	 */
	private static List<Parameter> parse(Reader reader) throws IOException {
		List<Parameter> parameters = new ArrayList<Parameter>();
		Parameter parameter = new Parameter();

		State state = State.NAME;
		for (;;) {
			int b = reader.read();
			if (b == -1) {
				// conclude last parameter value
				if (parameter.isEmpty()) {
					break;
				}
				if (parameters.isEmpty() && parameter.isRawValue()) {
					parameter.commitRawValue();
				} else {
					parameter.commitValue();
				}
				parameters.add(parameter);
				break;
			}
			char c = (char) b;

			switch (state) {
			case NAME:
				switch (c) {
				case '=':
					state = State.VALUE;
					parameter.commitName();
					break;

				case '&':
					if (parameter.getBuilder().isEmpty()) {
						throw new SyntaxException("Invalid query string. Empty parameter name.");
					} else {
						throw new SyntaxException("Invalid query string parameter |%s|. Missing name/value separator.", parameter.getBuilder());
					}

				default:
					parameter.append(c);
				}
				break;

			case VALUE:
				switch (c) {
				case '&':
					state = State.NAME;
					parameter.commitValue();
					parameters.add(parameter);
					parameter = new Parameter();
					break;

				case '=':
					throw new SyntaxException("Invalid query string parameter |%s|. Unescaped '=' character.", parameter.getBuilder());

				default:
					parameter.append(c);
				}
			}
		}

		return parameters;
	}

	/**
	 * Get an array of arguments suitable for a method invocation. This method did its best to fill the arguments array. The
	 * logic is simple: ignore query extra parameters and set to null the missing ones. Both cases are recorded to debug log.
	 * Returned arguments array has the same size as requested formal parameters array.
	 *

	 * Parameter values from parsed {@link #parameters} are converted to requested type using {@link #asObject(String, Type)}
	 * utility method. If formal parameters has a single type that has no converter uses reflection to map query parameters to
	 * object field by name.
	 *

	 * Note that because parameter names are not preserved on run-time, query parameters are mapped by position to invocation
	 * arguments. This means is caller responsibility to match formal parameters order and type with actual query string
	 * parameters.
	 *
	 * @param formalParameters formal parameters list.
	 * @return invocation arguments array.
	 * @throws ConverterException if string value cannot be converted to requested type.
	 * @throws BugError if type is generic and is not an array like.
	 */
	public Object[] getArguments(Type[] formalParameters) {
		if (formalParameters.length == 0) {
			return new Object[0];
		}
		Object[] arguments = new Object[formalParameters.length];

		if (isObject(formalParameters)) {
			// if there is single formal parameter and it is not a value type create object instance and initialize fields from
			// request parameters; object class should have no arguments constructor
			Class<?> type = (Class<?>) formalParameters[0];
			Object object = Classes.newInstance(type);
			for (Parameter parameter : parameters) {
				Field field = Classes.getField(type, Strings.toMemberName(parameter.getName()));
				Classes.setFieldValue(object, field, asObject(parameter.getValue(), field.getType()));
			}
			return new Object[] { object };
		}

		int i = 0, argumentsCount = Math.min(formalParameters.length, parameters.size());
		for (i = 0; i < argumentsCount; ++i) {
			arguments[i] = asObject(parameters.get(i).getValue(), formalParameters[i]);
		}
		for (; i < formalParameters.length; ++i) {
			log.debug("Missing request parameter |%s|. Set it to null.", i, formalParameters[i]);
			arguments[i] = null;
		}
		for (; i < parameters.size(); ++i) {
			log.debug("Unused request parameter |%s|. Ignore it.", parameters.get(i));
		}
		return arguments;
	}

	// --------------------------------------------------------------------------------------------
	// UTILITY METHODS

	/**
	 * Helper method to convert string parameter to an instance of a given type. Requested type should be a value
	 * type as accepted by converter package or an array / collection of value types. In the later case value
	 * should be a comma separated string of items. If given value is null returns an empty value as defined by
	 * {@link Types#getEmptyValue(Type)}.
	 *
	 * @param value parameter value, possible null,
	 * @param type parameter type.
	 * @param <T> instance type.
	 * @return newly created parameter type instance.
	 * @throws ConverterException if string value cannot be converted to requested type.
	 * @throws BugError if type is generic and is not an array like.
	 */
	@SuppressWarnings("unchecked")
	private static <T> T asObject(String value, Type type) {
		if (value == null) {
			return (T) Types.getEmptyValue(type);
		}

		if (!Types.isArrayLike(type)) {
			if (!(type instanceof Class)) {
				throw new BugError("Generic value types are not supported.");
			}
			if (ConverterRegistry.hasType(type)) {
				return ConverterRegistry.getConverter().asObject(value, (Class<T>) type);
			}
			log.debug("Missing converter for query parameter of type |%s|.", type);
			return (T) Types.getEmptyValue(type);
		}

		// here we have an array/collection represented as comma separated primitives
		List<String> strings = Strings.split(value, ',');
		if (type == String[].class) {
			return (T) strings.toArray(new String[strings.size()]);
		}
		if (Types.isKindOf(type, Collection.class)) {
			Type collectionType = type;
			Class<?> itemType = String.class;
			if (type instanceof ParameterizedType) {
				collectionType = ((ParameterizedType) type).getRawType();
				itemType = (Class<?>) ((ParameterizedType) type).getActualTypeArguments()[0];
			}
			Collection<Object> collection = Classes.newCollection(collectionType);
			Converter converter = ConverterRegistry.getConverter();
			for (String s : strings) {
				collection.add(converter.asObject(s.trim(), itemType));
			}
			return (T) collection;
		}

		throw new BugError("Type not supported |%s|.", type);
	}

	/**
	 * Test if method formal parameters designates a strict object, that is, is not primitive, array, collection or map.
	 *
	 * @param formalParameters method formal parameters list.
	 * @return true if formal parameters designates a strict object.
	 */
	private static boolean isObject(Type[] formalParameters) {
		if (formalParameters.length != 1) {
			return false;
		}
		final Type type = formalParameters[0];
		if (!(type instanceof Class)) {
			return false;
		}
		if (Types.isPrimitive(type)) {
			return false;
		}
		if (Types.isArrayLike(type)) {
			return false;
		}
		if (Types.isMap(type)) {
			return false;
		}
		if (ConverterRegistry.hasType(type)) {
			return false;
		}
		return true;
	}

	// --------------------------------------------------------------------------------------------
	// INNER CLASSES

	/**
	 * Query parameter wraps a single parameter from query string. It has a name and a value. This class is specifically
	 * designed for integration with query string parser. It has an internal string builder, used to collect characters from
	 * stream, for both parameter name and value, see {@link #append(char)}. Also has methods to control building life cycle:
	 * {@link #commitName()} marks name processing end and {@link #commitValue()} conclude entire parameter parsing.
	 *

	 * Because parameter instance has internal state that control string builder usage, it is not reusable. Create a new
	 * instance for every parameter from query string.
	 *
	 * @author Iulian Rotaru
	 * @version final
	 */
	private static class Parameter {
		/** String builder used for both parameter name and value. */
		private final StringBuilder builder = new StringBuilder();
		/** Parameter name. */
		private String name;
		/** Parameter value. */
		private String value;

		/**
		 * Append character to string builder.
		 *
		 * @param c character to add.
		 */
		public void append(char c) {
			builder.append(c);
		}

		/**
		 * Copy string builder content to parameter name and reset the builder.
		 *
		 * @throws SyntaxException if parameter name is empty.
		 * @throws UnsupportedEncodingException if name is not properly encoded UTF-8.
		 */
		public void commitName() throws UnsupportedEncodingException {
			if (builder.length() == 0) {
				throw new SyntaxException("Invalid query string. Empty parameter name.");
			}
			name = URLDecoder.decode(builder.toString(), "UTF-8");
			builder.setLength(0);
		}

		/**
		 * Decode string builder content and copy result to parameter value.
		 *
		 * @return true if parameter value was decoded.
		 * @throws SyntaxException if parameter name is null, most probably because of missing '=' separator.
		 * @throws UnsupportedEncodingException if value is not properly encoded UTF-8.
		 */
		public boolean commitValue() throws UnsupportedEncodingException {
			// name is null only if commit name was not invoked
			// if builder has some data but name is null then '=' separator was not found
			// this condition can occur only if query string ends before separator found

			// do not test for empty name since is already tested on commit name

			if (builder.length() > 0 && name == null) {
				throw new SyntaxException("Invalid query string parameter |%s|. Missing name/value separator.", builder.toString());
			}
			if (builder.length() == 0) {
				return false;
			}
			value = URLDecoder.decode(builder.toString(), "UTF-8");
			return true;
		}

		/**
		 * Commit raw value does actually copy internal builder content to this parameter value. Name is not used by raw values
		 * and is set to a neutral value.
		 *

		 * A raw value is a query parameter that does not respect query string syntax, that is, is a continuous string without
		 * name/value separator. Raw value is used as a simplified, not standard, alternative when there is a single parameter.
		 * For example, instead of using URL like .../captha/image?token=1234 is possbile to use
		 * .../captha/image?1234.
		 *
		 * @throws UnsupportedEncodingException if value is not properly encoded UTF-8.
		 */
		public void commitRawValue() throws UnsupportedEncodingException {
			name = "null";
			value = URLDecoder.decode(builder.toString(), "UTF-8");
		}

		/**
		 * Test if this parameter is empty.
		 *
		 * @return true if this parameter is empty.
		 */
		public boolean isEmpty() {
			return builder.length() == 0;
		}

		/**
		 * Test if this parameter is a raw value. A raw value has no name/value separator so {@link #commitName()} is not
		 * executed when this predicate is tested.
		 *
		 * @return true if this parameter is a raw value.
		 */
		public boolean isRawValue() {
			return name == null;
		}

		/**
		 * Get parameter name.
		 *
		 * @return parameter name;
		 */
		public String getName() {
			return name;
		}

		/**
		 * Get parameter value.
		 *
		 * @return parameter value.
		 */
		public String getValue() {
			return value;
		}

		/**
		 * Get string builder value, for debugging purposes.
		 *
		 * @return builder content.
		 */
		public String getBuilder() {
			return builder.toString();
		}
	}

	/**
	 * States for query parameters parser.
	 *
	 * @author Iulian Rotaru
	 * @version final
	 */
	private static enum State {
		/** Processing parameter name. */
		NAME,
		/** Processing parameter value. */
		VALUE
	}
}


package js.http.encoder;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.nio.charset.Charset;

import javax.servlet.http.HttpServletRequest;

import js.json.Json;
import js.json.JsonException;
import js.lang.IllegalArgumentException;
import js.util.Classes;
import js.util.Types;

/**
 * JSON arguments reader for both invocation and multipart body entity. This arguments reader implementation delegates
 * {@link Json} for actual arguments parsing. It is used by servlets for method invocation arguments read and by
 * {@link MultipartMixedArgumentsReader} for entity body parsing when encoded JSON.
 *
 * @author Iulian Rotaru
 * @version final
 */
final class JsonArgumentsReader implements ArgumentsReader, ArgumentPartReader {
	/** JSON deserializer delegated for arguments parsing. */
	private final Json json;

	/** Create JSON arguments reader. */
	public JsonArgumentsReader() {
		json = Classes.loadService(Json.class);
	}

	/**
	 * Uses JSON deserializer to parse method invocation arguments accordingly formal parameters list.
	 *
	 * @param httpRequest HTTP request,
	 * @param formalParameters formal parameter types.
	 * @return arguments array.
	 * @throws IOException if reading from request input stream fails.
	 * @throws IllegalArgumentException if arguments from HTTP request cannot be parsed.
	 * @throws JsonException if JSON parsing fails due to invalid stream format.
	 */
	@Override
	public Object[] read(HttpServletRequest httpRequest, Type[] formalParameters) throws IOException, IllegalArgumentException {
		JsonReader reader = new JsonReader(httpRequest.getInputStream(), expectedStartSequence(formalParameters));
		try {
			return json.parse(reader, formalParameters);
		} catch (JsonException e) {
			throw new IllegalArgumentException(e.getMessage());
		} finally {
			reader.close();
		}
	}

	/**
	 * Parse JSON from input stream accordingly given type. Return parsed object.
	 *
	 * @param inputStream JSON input stream,
	 * @param type expected type.
	 * @return parsed object.
	 * @throws IllegalArgumentException if JSON parse or reading from stream fails.
	 */
	@Override
	public Object read(InputStream inputStream, Type type) throws IOException {
		try {
			return json.parse(new InputStreamReader(inputStream, "UTF-8"), type);
		} catch (JsonException | ClassCastException | UnsupportedEncodingException e) {
			throw new IllegalArgumentException(e.getMessage());
		}
	}

	/** This method does nothing but is requested by interface. */
	@Override
	public void clean() {
	}

	private static String expectedStartSequence(Type[] formalParameters) {
		if (formalParameters.length == 0) {
			return "[";
		}
		StringBuilder builder = new StringBuilder();
		builder.append('[');
		Type parameter = formalParameters[0];
		while (Types.isArrayLike(parameter)) {
			builder.append('[');
			if (!(parameter instanceof ParameterizedType)) {
				break;
			}
			ParameterizedType parameterizedType = (ParameterizedType) parameter;
			parameter = parameterizedType.getActualTypeArguments()[0];
		}
		return builder.toString();
	}

	/**
	 * JSON stream reader with mark symbol detection. Mark symbol is the first character from JSON stream and is used to detect
	 * if JSON is an array. If is not an array it should be object or primitive.
	 *
	 * @author Iulian Rotaru
	 * @version final
	 */
	private static class JsonReader extends Reader {
		/** Underlying JSON reader. */
		private final Reader reader;

		private final String expectedStartSequence;

		private final StringBuilder startSequenceBuffer;

		private boolean correctStartSequence;

		private int startSequenceOffset;

		private State state;

		/**
		 * Create JSON reader for given bytes stream encoded UTF-8.
		 *
		 * @param inputStream JSON bytes input stream.
		 * @throws IOException if mark symbol reading fails.
		 */
		public JsonReader(InputStream inputStream, String expectedStartSequence) throws IOException {
			this(new InputStreamReader(inputStream, Charset.forName("UTF-8")), expectedStartSequence);
		}

		/**
		 * Create JSON reader for given characters stream. Reads first character from JSON stream and uses it to detect if
		 * stream is an array.
		 *
		 * @param reader JSON reader.
		 * @throws IOException if mark symbol reading fails.
		 */
		public JsonReader(Reader reader, String expectedStartSequence) throws IOException {
			super();
			this.reader = reader;
			this.expectedStartSequence = expectedStartSequence;
			this.startSequenceBuffer = new StringBuilder();
			this.state = State.BUFFER_FILL;
		}

		/**
		 * Read characters from JSON stream. On first invocation of this method uses inner {@link MarkReader}. After that
		 * internal reader reference is replaced with wrapped JSON reader provided to this instance constructor.
		 *
		 * @param cbuf destination buffer,
		 * @param off offset at which to start storing characters,
		 * @param len maximum number of characters to read.
		 * @return number of characters read.
		 */
		@Override
		public int read(char[] cbuf, int off, int len) throws IOException {
			if (len == 0) {
				return 0;
			}

			int charsCount = -1;
			switch (state) {
			case BUFFER_FILL:
				// fill synchronously the start sequence buffer
				for (;;) {
					int c = reader.read();
					if (c == -1) {
						return -1;
					}
					startSequenceBuffer.append((char) c);
					if (c != '[') {
						break;
					}
				}

				// asses and cache loaded start sequence correctness
				correctStartSequence = expectedStartSequence.equals(startSequenceBuffer.substring(0, startSequenceBuffer.length() - 1));

				// if start sequence is not the correct assume is a JSON stream without arguments array markers
				if (!correctStartSequence) {
					startSequenceBuffer.insert(0, '[');
				}
				startSequenceOffset = 0;
				state = State.BUFFER_READ;
				// fall through buffer read

			case BUFFER_READ:
				charsCount = Math.min(startSequenceBuffer.length() - startSequenceOffset, len);
				for (int i = 0; i < charsCount; ++i, ++startSequenceOffset) {
					cbuf[off + i] = startSequenceBuffer.charAt(startSequenceOffset);
				}

				if (startSequenceOffset == startSequenceBuffer.length()) {
					// entire start sequence was sent to parser, that is, caller of this read method
					state = correctStartSequence ? State.STANDARD_READ : State.ENHANCED_READ;
				}
				break;

			case STANDARD_READ:
				return reader.read(cbuf, off, len);

			case ENHANCED_READ:
				charsCount = reader.read(cbuf, off, len);
				if (charsCount == -1) {
					state = State.EOF;
					cbuf[off] = ']';
					return 1;
				}
				break;

			case EOF:
				return -1;
			}
			return charsCount;
		}

		/** This method does nothing since JSON reader is closed by outer logic. */
		@Override
		public void close() throws IOException {
		}

		/**
		 * States for JSON reader finite states machine.
		 *
		 * @author Iulian Rotaru
		 */
		private enum State {
			/**
			 * Fill start sequence buffer. On this state characters read from underlying stream are stored into start sequence
			 * buffer.
			 */
			BUFFER_FILL,
			/** Read characters from start sequence buffer. */
			BUFFER_READ,
			/** Read characters from underlying stream to caller buffer. */
			STANDARD_READ,
			/** The same as standard read but takes care to detect EOF and append ']' */
			ENHANCED_READ,
			/**
			 * Simply returns -1 to signal EOF condition. This state is reached only after enhanced reading was properly close
			 * stream with ']'.
			 */
			EOF
		}
	}
}