package js.container;

import java.lang.reflect.Constructor;
import java.lang.reflect.Member;
import java.lang.reflect.Method;

import js.lang.IllegalArgumentException;
import js.lang.VarArgs;
import js.util.Types;

/**
 * Pre-process constructor or method invocation arguments. This processor is used when new managed instance is created or a
 * managed method is about to be invoked. It injects dependencies if formal parameters are required but no invocation arguments
 * provided. Also performs arguments validity check against formal parameters throwing illegal arguments if validation fails.
 *
 * @author Iulian Rotaru
 * @version final
 */
final class ArgumentsProcessor extends DependencyProcessor {
	/** Reusable empty arguments used when provided arguments array is null. */
	private static final Object[] EMPTY_ARGS = new Object[0];

	/**
	 * Pre-process constructor arguments for local managed classes. A managed class is local if is of
	 * {@link InstanceType#POJO} or {@link InstanceType#PROXY} type. Attempting to pre-process arguments for other managed class
	 * types is silently ignored. This method delegates
	 * {@link #preProcessArguments(ManagedClassSPI, Member, Class[], Object...)}.
	 *
	 * @param managedClass managed class,
	 * @param args constructor arguments.
	 * @return processed arguments.
	 */
	public Object[] preProcessArguments(ManagedClassSPI managedClass, Object... args) {
		// arguments can be null if on invocations chain there is Proxy handler invoked with no arguments
		if (args == null) {
			args = EMPTY_ARGS;
		}
		if (managedClass.getImplementationClass() == null) {
			return args;
		}
		Constructor<?> constructor = managedClass.getConstructor();

		// managed class constructor parameters have the same limitation as injected fields: they must be a managed
		// class on their turn; it is considered a bug trying to use not managed classes as constructor argument

		// because managed class is not generic is safe to use getParameterTypes instead of getGenericParameterTypes
		final Class<?>[] types = constructor.getParameterTypes();
		return preProcessArguments(managedClass, constructor, types, args);
	}

	/**
	 * Pre-process managed method invocation arguments. This processor prepares invocation arguments for given managed method;
	 * it just delegates {@link #preProcessArguments(ManagedClassSPI, Member, Class[], Object...)}.
	 *
	 * @param managedMethod managed method,
	 * @param args method invocation arguments.
	 * @return processed arguments.
	 */
	public Object[] preProcessArguments(ManagedMethodSPI managedMethod, Object... args) {
		// arguments can be null if on invocations chain there is Proxy handler invoked with no arguments
		if (args == null) {
			args = EMPTY_ARGS;
		}

		final ManagedClassSPI managedClass = managedMethod.getDeclaringClass();
		final Method method = managedMethod.getMethod();
		final Class<?>[] types = method.getParameterTypes();
		return preProcessArguments(managedClass, method, types, args);
	}

	/**
	 * Update and validate invocation arguments against given formal parameter types. If formal parameters is not empty but no
	 * invocation arguments this method will inject dependency using {@link #getDependencyValue(ManagedClassSPI, Class)}. This
	 * method also performs arguments validity check against formal parameters throwing illegal arguments if validation fails.
	 *
	 * @param managedClass managed class owning constructor or method,
	 * @param member constructor or method for given arguments,
	 * @param formalParameters formal parameter types,
	 * @param args constructor or method invocation arguments.
	 * @return given arguments updated and validated.
	 */
	private static Object[] preProcessArguments(ManagedClassSPI managedClass, Member member, Class<?>[] formalParameters, Object... args) {
		switch (args.length) {
		case 0:
			args = new Object[formalParameters.length];
			for (int i = 0; i < args.length; i++) {
				args[i] = getDependencyValue(managedClass, formalParameters[i]);
			}
			break;

		case 1:
			// TODO: refine variable arguments: test for formal parameters type, document and test
			if (args[0] instanceof VarArgs && formalParameters.length == 1 && formalParameters[0].isArray()) {
				args[0] = ((VarArgs<?>) args[0]).getArguments();
			}
			break;
		}

		// arguments validity test against formal parameters: count and types
		if (formalParameters.length != args.length) {
			throw new IllegalArgumentException("Invalid arguments count on method |%s|. Expected |%d| but got |%d|.", member, formalParameters.length, args.length);
		}
		for (int i = 0; i < formalParameters.length; ++i) {
			if (args[i] != null && !Types.isInstanceOf(args[i], formalParameters[i])) {
				throw new IllegalArgumentException("Invalid argument type at position |%d| on method |%s|. Expected |%s| but got |%s|.", i, member, formalParameters[i], args[i].getClass());
			}
		}
		return args;
	}
}


/*
 * 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.util;/*
 * Copyright (c) 2009-2015  Cologne Intelligence GmbH
 * 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/>.
 */

import de.cologneintelligence.fitgoodies.htmlparser.FitCell;

import java.io.File;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class FitUtils {

	private FitUtils() {
	}

	private static Pattern PARAMETER_PATTERN = Pattern.compile("^(.*)\\s*\\[\\s*(.*?)\\s*\\]\\s*$");
	private static Pattern MULTI_PARAMETER_PATTERN = Pattern.compile("^\\s*([^=]+?)\\s*=\\s*(.*?)\\s*$");

	public static String HTML_GREEN = "#cfffcf";
	public static String HTML_RED = "#ffcfcf";
	public static String HTML_GREY = "#efefef";
	public static String HTML_YELLOW = "#ffffcf";
	public static String HTML_INFO = "#808080";

	public static String label(String string) {
		return " " + string + "";
	}

	public static String escape(String string) {
		string = string.replaceAll("&", "&");
		string = string.replaceAll("<", "<");
		string = string.replaceAll("  ", "  ");
		string = string.replaceAll("\r\n", "
");
		string = string.replaceAll("\r", "
");
		string = string.replaceAll("\n", "
");
		return string;
	}

	public static String camel(String name) {
		StringBuilder b = new StringBuilder(name.length());
		StringTokenizer t = new StringTokenizer(name);
		if (!t.hasMoreTokens())
			return name;
		b.append(t.nextToken());
		while (t.hasMoreTokens()) {
			String token = t.nextToken();
			b.append(token.substring(0, 1).toUpperCase());      // replace spaces with camelCase
			b.append(token.substring(1));
		}
		return b.toString();
	}

	public static String htmlSafeFile(File file) {
		return htmlSafeFile(file.getPath());
	}

	public static String htmlSafeFile(String file) {
		return file.replace(File.separatorChar, '/');
	}

	public static <T> T saveGet(int col, T[] array) {
		if (col < array.length) {
			return array[col];
		} else {
			return null;
		}
	}

	/**
	 * extracts and removes parameters from a cell.
	 *
	 * @param cell cell to process
	 * @return the extracted parameter or {@code null}
	 */
	public static String extractCellParameter(FitCell cell) {
		final Matcher matcher = PARAMETER_PATTERN.matcher(cell.getFitValue());
		if (matcher.matches()) {
			cell.setFitValue(matcher.group(1));
			return matcher.group(2);
		} else {
			return null;
		}
	}

	public static Map<String, String> extractCellParameterMap(FitCell cell) {
		String parameters = extractCellParameter(cell);
		if (parameters == null) {
			return Collections.emptyMap();
		}

		Map<String, String> result = new HashMap<>();
		for (String keyValue : parameters.split(",")) {
			Matcher matcher = MULTI_PARAMETER_PATTERN.matcher(keyValue);

			if (matcher.find()) {
				result.put(matcher.group(1), matcher.group(2));
			}
		}

		return result;
	}
}


/*
 * 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;

import de.cologneintelligence.fitgoodies.alias.AliasHelper;
import de.cologneintelligence.fitgoodies.htmlparser.FitDocument;
import de.cologneintelligence.fitgoodies.htmlparser.FitTable;
import de.cologneintelligence.fitgoodies.util.DependencyManager;
import de.cologneintelligence.fitgoodies.util.RunTime;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class FixtureRunner {

	public Map<String, Object> summary = new HashMap<>();
	public Counts counts = new Counts();

	/* Altered by Rick Mugridge to dispatch on the first Fixture */
	public void doDocument(FitDocument document) {
		summary.put("run date", new Date());
		summary.put("run elapsed time", new RunTime());
		if (document != null) {
			interpretTables(document);
		}
	}

	/* Added by Rick Mugridge */
	private void interpretTables(FitDocument documents) {
        for (FitTable table : documents.tables()) {
            try {
                Fixture fixture = getLinkedFixtureWithArgs(table);
                fixture.doTable(table);
                counts.tally(table.getCounts());
            } catch (Throwable e) {
                table.exception(e);
                counts.exceptions++;
            }
		}
	}

	/* Added from FitNesse*/
	protected Fixture getLinkedFixtureWithArgs(FitTable table) {
		Fixture fixture = loadFixture(table.getFixtureClass());
		fixture.setParams(getArgsForTable(table));
		return fixture;
	}

    /**
     * Loads a fixutre by its fully quallified {@code className}.
     * If the {@code className} is an alias, the referenced class is used.
     *
     * @param fixtureName name of the fixture to load.
     * @return instance of the class which is referenced by {@code fixtureName}
     * @throws RuntimeException propagated to fit,
     *                          thrown if something different went wrong
     */
    private Fixture loadFixture(final String fixtureName) {
        AliasHelper helper = DependencyManager.getOrCreate(AliasHelper.class);
        String realName = helper.getClazz(fixtureName);

        return loadFixtureByName(realName);
    }

	private Fixture loadFixtureByName(String fixtureName) {
		try {
			return (Fixture) (Class.forName(fixtureName).newInstance());
		} catch (ClassCastException e) {
			throw new RuntimeException("\"" + fixtureName + "\" was found, but it's not a fixture.", e);
		} catch (ClassNotFoundException | NoClassDefFoundError e) {
			throw new RuntimeException("The fixture \"" + fixtureName + "\" was not found.", e);
		} catch (InstantiationException | IllegalAccessException e) {
			throw new RuntimeException("The fixture \"" + fixtureName + "\" could not be instantiated.", e);
		}
	}

	/* Added by Rick Mugridge, from FitNesse */
	protected Map<String, String> getArgsForTable(FitTable table) {
        return table.getArguments();
	}
}


/*
 * 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.mail;

import de.cologneintelligence.fitgoodies.ActionFixture;
import de.cologneintelligence.fitgoodies.typehandler.BooleanTypeHandler;
import de.cologneintelligence.fitgoodies.util.DependencyManager;

/**
 * This fixture is used to define a connection to an e-mail provider.
 * The connection is not opened, this happens when the {@link MailFixture}
 * is used.
 *

 * Setup example:
 *

 *
fitgoodies.mail.SetupFixture

 *
protocol	imap

 *
host	imapserver.mycompany.com

 *
port	993

 *
ssl	true

 *
username	user

 *
password	pass

 *
inbox	INBOX.Testfolder

 *

 *

 * Shorter example (no ssl, standard port):
 *

 *
fitgoodies.mail.SetupFixture

 *
protocol	pop3

 *
host	pop3server.mycompany.com

 *
username	user

 *
password	pass

 *

 */
public class SetupFixture extends ActionFixture {

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

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

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

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

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

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

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

	/**
	 * Sets the SSL parameter of the mail {@link SetupHelper}.
	 *
	 * @param ssl indicates whether SSL shall be used
	 * @see SetupHelper#setSSL(boolean) SetupHelper.setSSL(boolean)
	 */
	public void ssl(final String ssl) {
		DependencyManager.getOrCreate(SetupHelper.class)
				.setSSL(BooleanTypeHandler.parseBool(ssl));
	}

	/**
	 * Sets the port parameter of the mail {@link SetupHelper}.
	 *
	 * @param port port to use
	 * @see SetupHelper#setPort(int) SetupHelper.setPort(int)
	 */
	public void port(final String port) {
		DependencyManager.getOrCreate(SetupHelper.class)
				.setPort(Integer.parseInt(port));
	}

	/**
	 * Sets the inbox parameter of the mail {@link SetupHelper}.
	 *
	 * @param inbox inbox to use
	 * @see SetupHelper#setInbox(String) SetupHelper.setInbox(String)
	 */
	public void inbox(final String inbox) {
		DependencyManager.getOrCreate(SetupHelper.class)
				.setInbox(inbox);
	}

	/**
	 * Sets the host parameter if the mail {@link SetupFixture}.
	 *
	 * @param host host to use
	 * @see SetupHelper#setHost(String) SetupHelper.setHost(String)
	 */
	public void host(final String host) {
		DependencyManager.getOrCreate(SetupHelper.class)
				.setHost(host);
	}

	/**
	 * Sets the user name parameter if the mail {@link SetupFixture}.
	 *
	 * @param username user name to use
	 * @see SetupHelper#setUsername(String) SetupHelper.setUsername(String)
	 */
	public void username(final String username) {
		DependencyManager.getOrCreate(SetupHelper.class)
				.setUsername(username);
	}

	/**
	 * Sets the password parameter if the mail {@link SetupFixture}.
	 *
	 * @param password password to use
	 * @see SetupHelper#setPassword(String) SetupHelper.setPassword(String)
	 */
	public void password(final String password) {
		DependencyManager.getOrCreate(SetupHelper.class)
				.setPassword(password);
	}

	/**
	 * Sets the protocol parameter if the mail {@link SetupFixture}.
	 *
	 * @param protocol protocol to use
	 * @see SetupHelper#setProtocol(String) SetupHelper.setProtocol(String)
	 */
	public void protocol(final String protocol) {
		DependencyManager.getOrCreate(SetupHelper.class)
				.setProtocol(protocol);
	}
}


package js.http;

import javax.servlet.http.HttpServletRequest;

/**
 * HTTP headers constants and related helpers.
 *
 * @author Iulian Rotaru
 * @version final
 */
public class HttpHeader {
	/** Content-Types that are acceptable for the response. */
	public static final String ACCEPT = "Accept";
	/** Character sets that are acceptable. */
	public static final String ACCEPT_CHARSET = "Accept-Charset";
	/** List of acceptable encodings. */
	public static final String ACCEPT_ENCODING = "Accept-Encoding";
	/** List of acceptable human languages for response. */
	public static final String ACCEPT_LANGUAGE = "Accept-Language";
	/** Authentication credentials for HTTP authentication. */
	public static final String AUTHORIZATION = "Authorization";
	/** Used to specify directives that must be obeyed by all caching mechanisms along the request-response chain. */
	public static final String CACHE_CONTROL = "Cache-Control";
	/** An HTTP cookie previously sent by the server with Set-Cookie. */
	public static final String COOKIE = "Cookie";
	/** Controls whether or not the network connection stays open after the current transaction finishes. */
	public static final String CONNECTION = "Connection";
	/** The type of encoding used on the data. */
	public static final String CONTENT_ENCODING = "Content-Encoding";
	/** The natural language or languages of the intended audience for the enclosed content. */
	public static final String CONTENT_LANGUAGE = "Content-Language";
	/** The length of the response body in 8-bit bytes. */
	public static final String CONTENT_LENGTH = "Content-Length";
	/** An alternate location for the returned data. */
	public static final String CONTENT_LOCATION = "Content-Location";
	/** The MIME type of the body of the HTTP message. */
	public static final String CONTENT_TYPE = "Content-Type";
	/** The date and time that the message was originated, RFC 7231 Date/Time Formats. */
	public static final String DATE = "Date";
	/** An identifier for a specific version of a resource, often a message digest. */
	public static final String ETAG = "ETag";
	/** Gives the date/time after which the response is considered stale, RFC 7231 Date/Time Formats. */
	public static final String EXPIRES = "Expires";
	/**
	 * The domain name of the server (for virtual hosting), and the TCP port number on which the server is listening. The port
	 * number may be omitted if the port is the standard port for the service requested.
	 */
	public static final String HOST = "Host";
	/** Only perform the action if the client supplied entity matches the same entity on the server. */
	public static final String IF_MATCH = "If-Match";
	/** Allows a 304 Not Modified to be returned if content is unchanged. */
	public static final String IF_MODIFIED_SINCE = "If-Modified-Since";
	/** Allows a 304 Not Modified to be returned if content is unchanged. */
	public static final String IF_NONE_MATCH = "If-None-Match";
	/** Only send the response if the entity has not been modified since a specific time. */
	public static final String IF_UNMODIFIED_SINCE = "If-Unmodified-Since";
	/** Used in redirection, or when a new resource has been created. */
	public static final String LOCATION = "Location";
	/** Implementation-specific fields that may have various effects anywhere along the request-response chain. */
	public static final String PRAGMA = "Pragma";
	/** This is the address of the previous web page from which a link to the currently requested page was followed. */
	public static final String REFERER = "Referer";
	/** SOAP action encoded into HTTP header. */
	public static final String SOAP_ACTION = "SOAPAction";
	/** The user agent string of the user agent. */
	public static final String USER_AGENT = "User-Agent";
	/**
	 * Tells downstream proxies how to match future request headers to decide whether the cached response can be used rather
	 * than requesting a fresh one from the origin server.
	 */
	public static final String VARY = "Vary";
	/** Indicates the authentication scheme that should be used to access the requested entity. */
	public static final String WWW_AUTHENTICATE = "WWW-Authenticate";
	/** An HTTP cookie. */
	public static final String SET_COOKIE = "Set-Cookie";
	/** j(s)-lib extension header for location redirect via 200 OK. */
	public static final String X_HEADER_LOCATION = "X-JSLIB-Location";
	/** Mainly used to identify AJAX requests. */
	public static final String X_REQUESTED_WITH = "X-Requested-With";

	/** Value for Connection header that requires to keep network connection opened after current HTTP transaction ends. */
	public static final String KEEP_ALIVE = "keep-alive";

	/** Cache control header value for disabled cache. */
	public static final String NO_CACHE = "no-cache";
	/** Cache control header value for disabled cache. */
	public static final String NO_STORE = "no-store";

	/** Header value for requested with AJAX. */
	private static final String XML_HTTP_REQUEST = "XMLHttpRequest";
	/** Header value for requested from Android library. */
	private static final String ANDROID_USER_AGENT = "j(s)-lib android";

	/** Prevent default constructor synthesis but allow sub-classing. */
	protected HttpHeader() {
	}

	/**
	 * Test if given HTTP request is performed via XMLHttpRequest.
	 *
	 * @param httpRequest HTTP request.
	 * @return true if X-Requested-With header is XMLHttpRequest.
	 */
	public static boolean isXHR(HttpServletRequest httpRequest) {
		String requestedWith = httpRequest.getHeader(X_REQUESTED_WITH);
		return requestedWith != null ? requestedWith.equalsIgnoreCase(XML_HTTP_REQUEST) : false;
	}

	/**
	 * Test if HTTP request is from Android.
	 *
	 * @param httpRequest HTTP request.
	 * @return true if X-Requested-With header contains j(s)-lib android signature.
	 */
	public static boolean isAndroid(HttpServletRequest httpRequest) {
		String requestedWith = httpRequest.getHeader(X_REQUESTED_WITH);
		return requestedWith != null ? requestedWith.equalsIgnoreCase(ANDROID_USER_AGENT) : false;
	}

	/**
	 * Predicate to test for SOAP request. Accordingly SOAP specifications every SOAP request MUST include SOAPAction header.
	 *
	 * @param httpRequest HTTP request.
	 * @return true if SOAPAction header is present.
	 */
	public static boolean isSOAP(HttpServletRequest httpRequest) {
		return httpRequest.getHeader(SOAP_ACTION) != null;
	}
}


package js.http.encoder;

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

import javax.servlet.http.HttpServletRequest;

/**
 * Special arguments reader for methods with no formal parameters.
 *
 * @author Iulian Rotaru
 * @version final
 */
public class EmptyArgumentsReader implements ArgumentsReader {
	/** Shared empty arguments array. */
	private static final Object[] EMPTY_ARGUMENTS = new Object[] {};

	/** Reusable instance of empty arguments reader. */
	private static EmptyArgumentsReader instance = new EmptyArgumentsReader();

	/**
	 * Get empty arguments reader.
	 *
	 * @return empty arguments reader singleton.
	 */
	public static EmptyArgumentsReader getInstance() {
		return instance;
	}

	/**
	 * This method is enacted for empty formal parameters. It just return {@link #EMPTY_ARGUMENTS}.
	 *
	 * @param httpRequest unused HTTP request,
	 * @param formalParameters unused empty formal parameters list.
	 * @return always return {@link #EMPTY_ARGUMENTS}.
	 */
	@Override
	public Object[] read(HttpServletRequest httpRequest, Type[] formalParameters) throws IOException, IllegalArgumentException {
		return EMPTY_ARGUMENTS;
	}

	/** 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;

import de.cologneintelligence.fitgoodies.htmlparser.FitCell;
import de.cologneintelligence.fitgoodies.htmlparser.FitRow;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

public class TimedActionFixture extends ActionFixture {

	public static final DateFormat format = new SimpleDateFormat("HH:mm:ss");
    static {
        format.setTimeZone(TimeZone.getTimeZone("GMT"));
    }

	// Traversal ////////////////////////////////

    @Override
    protected void doRow(FitRow row) throws Exception {
		Date start = time();
		super.doRow(row);
		long split = time().getTime() - start.getTime();

        FitCell cell = row.append();
        cell.setDisplayValue(format.format(start));
        cell.info("time");

        cell = row.append();
        cell.setDisplayValueRaw(split < 1000 ? " " : Double.toString((split) / 1000.0));
        cell.info("split");
	}

	// Utility //////////////////////////////////

	public Date time() {
		return new Date();
	}

}


package de.cologneintelligence.fitgoodies.htmlparser;

import de.cologneintelligence.fitgoodies.Counts;
import org.jsoup.nodes.Attribute;
import org.jsoup.nodes.Element;
import org.jsoup.parser.Tag;
import org.jsoup.select.Elements;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class FitTable {

	public static final Pattern ARGUMENT_PATTERN = Pattern.compile("^\\s*([^=]+?)\\s*=\\s*(.*?)\\s*$");

	private final Element table;
    private final String TAG = "tr";
    private boolean newStyleTable;
	private final Counts counts = new Counts();

	private boolean hasFeedbackColumn;
	private Map<Integer, State> errorColumnStates = new HashMap<>();
	private Map<Integer, String> errorColumnMessages = new HashMap<>();

	private String fixtureClass;
	private Map<String, String> arguments;
	private List<FitRow> rows = new LinkedList<>();
    private int contentStartPosition;

    public FitTable(Element table) {
		this.table = table;

		if (!checkTable()) {
			finishExecution();
			throw new IllegalArgumentException("Table is not valid");
		}

		parseTable();
	}

	private void parseTable() {
		Map<String, String> args = new HashMap<>();

		Elements trs = table.select("tr");
		newStyleTable = table.hasAttr(Constants.ATTR_FIXTURE);

        if (newStyleTable) {
			parseNewStyleHeader(args);
            contentStartPosition = 0;
		} else {
			parseOldStyleHeader(trs.first(), args);
            contentStartPosition = 1;
		}

		arguments = Collections.unmodifiableMap(args);

        for (Element tr : trs.subList(contentStartPosition, trs.size())) {
	        if (!ParserUtils.isIgnored(tr)) {
		        rows.add(new FitRow(this, tr));
	        }
        }
        updateIndices();
    }

    private boolean checkTable() {
		Elements trs = table.select("tr");
		if (trs.size() == 0 || trs.select("td").size() == 0) {
			exception("Incomplete table definition");
			return false;
		}

		return true;
	}

	private void parseOldStyleHeader(Element tr, Map<String, String> args) {
		final Elements tds = tr.select("td");
		fixtureClass = tds.first().text();

		List<Element> subList = tds.subList(1, tds.size());
		for (int i = 0; i < subList.size(); i++) {
			Element element = subList.get(i);

			Matcher matcher = ARGUMENT_PATTERN.matcher(element.text());
			if (matcher.find()) {
				args.put(matcher.group(1).toLowerCase(), matcher.group(2));
				args.put(Integer.toString(i), matcher.group(2));
			} else {
				args.put(Integer.toString(i), element.text());
			}
		}
	}

	private void parseNewStyleHeader(Map<String, String> args) {
		fixtureClass = table.attr(Constants.ATTR_FIXTURE);

		for (Attribute attribute : table.attributes()) {
			final String attributeName = attribute.getKey().toLowerCase();
			if (attributeName.startsWith(Constants.ATTR_ARGUMENT_PREFIX)) {
				args.put(attributeName.substring(Constants.ATTR_ARGUMENT_PREFIX.length()),
						attribute.getValue());
			}
		}
	}

	public Element getTable() {
		return table;
	}

	public List<FitRow> rows() {
		return Collections.unmodifiableList(rows);
	}

	public String getFixtureClass() {
		return fixtureClass;
	}

	public Map<String, String> getArguments() {
		return arguments;
	}

	public Counts getCounts() {
		return counts;
	}

	public void finishExecution() {
		processRowErrors();

		for (FitRow row : rows) {
			for (FitCell cell : row.cells()) {
				cell.finishExecution(counts);
			}
		}

		if (counts.exceptions > 0) {
			table.addClass(Constants.CSS_EXCEPTION);
		} else if (counts.wrong > 0) {
			table.addClass(Constants.CSS_WRONG);
		} else {
			table.addClass(Constants.CSS_RIGHT);
		}
	}

	private void processRowErrors() {
		if (!errorColumnStates.isEmpty()) {
			addFeedbackColumn(false);
			for (Map.Entry<Integer, String> entry : errorColumnMessages.entrySet()) {
				Element td = rows.get(entry.getKey()).getRow().select("td").first();
				State state = errorColumnStates.get(entry.getKey());

				td.text(entry.getValue());
				td.addClass(state.cssClass);

				if (state == State.EXCEPTION) {
					counts.exceptions++;
				} else {
					counts.wrong++;
				}
			}
		}
	}

	public void exception(Throwable t) {
		exception(ParserUtils.getHtmlStackTrace(t));
	}

	private void exception(String html) {
		addFeedbackColumn(true);
		counts.exceptions++;

		Element firstTd = table.select("tr").first().select("td").first();
		firstTd
				.html(html)
				.addClass(Constants.CSS_EXCEPTION);
	}

	private void addFeedbackColumn(boolean newRow) {
		if (hasFeedbackColumn) {
			return;
		}

		hasFeedbackColumn = true;

		if (table.select("tr").size() == 0 || (newStyleTable && newRow)) {
			table.prependElement("tr");
		}

		for (Element tr : table.select("tr")) {
			tr.prependElement("td")
					.addClass(Constants.CSS_FEEDBACK_COLUMN);
		}
	}

	void exceptionRow(int row, String text) {
		errorColumnMessages.put(row, text);
		errorColumnStates.put(row, State.EXCEPTION);
	}

	void wrongRow(int row, String text) {
		if (!errorColumnStates.containsKey(row) || !errorColumnStates.get(row).equals(State.EXCEPTION)) {
			errorColumnMessages.put(row, text);
			errorColumnStates.put(row, State.WRONG);
		}
	}

    // FIXME: test!
    public FitRow appendRow() {
        return insert(rows.size());
    }

    // FIXME: test!
    public void remove(int index) {
        table.select(TAG).get(index + contentStartPosition).remove();
        rows.remove(index);
        updateIndices();
    }

    // FIXME: test!
    public FitRow insert(int index) {
        Element tr = new Element(Tag.valueOf(TAG), table.baseUri());
        FitRow row = new FitRow(this, tr);

        Element tbody = table.select("tbody").first();
        tbody.insertChildren(index + contentStartPosition, Collections.singleton(tr));
        rows.add(index, row);
        updateIndices();

        return row;
    }

    private void updateIndices() {
        for (int i = 0; i < rows.size(); i++) {
            rows.get(i).updateIndex(i);
        }
    }

    public String pretty() {
        StringBuilder b = new StringBuilder();

        for (Element tr : table.select("tr")) {
            for (Element td : tr.select("td")) {
                b.append(td.text()).append(" | ");
            }
            b.append("\n");
        }

        return b.toString();
    }
}


package js.http.encoder;

import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import javax.servlet.http.HttpServletRequest;

import js.lang.IllegalArgumentException;
import js.util.Files;

/**
 * Provide application access to HTTP request input stream. This arguments reader mitigates application access to HTTP request
 * input stream via a Java type supported by {@link StreamFactory}.
 *
 * @author Iulian Rotaru
 * @version final
 */
final class StreamArgumentsReader implements ArgumentsReader, ArgumentPartReader {
	/**
	 * Cache closeable object till HTTP request is processed by application logic, in order to close it after. See
	 * {@link #clean()}. Uses thread local storage since arguments reader instance is reusable and cannot hold state.
	 */
	private final ThreadLocal<Closeable> threadLocal = new ThreadLocal<Closeable>();

	/**
	 * Provides application access to HTTP request input stream. Formal parameters should have only one type that is supported
	 * by {@link StreamFactory} otherwise illegal argument exception is thrown.
	 *
	 * @param httpRequest HTTP request,
	 * @param formalParameters formal parameter types.
	 * @return arguments array.
	 * @throws IOException if opening HTTP request input stream fails.
	 * @throws IllegalArgumentException if formal parameters does not contain exactly one type.
	 * @throws IllegalArgumentException if formal parameter type is parameterized.
	 * @throws IllegalArgumentException if formal parameter type is not supported by {@link StreamFactory}.
	 */
	@Override
	public Object[] read(HttpServletRequest httpRequest, Type[] formalParameters) throws IOException, IllegalArgumentException {
		if (formalParameters.length != 1) {
			throw new IllegalArgumentException("Bad parameters count for multipart form. Method must have exactly one formal parameter but has |%d|.", formalParameters.length);
		}
		if (formalParameters[0] instanceof ParameterizedType) {
			throw new IllegalArgumentException("Current implementation does not support parameterized types |%s|.", formalParameters[0]);
		}
		return new Object[] { read(httpRequest.getInputStream(), formalParameters[0]) };
	}

	/**
	 * This method is a this wrapper for {@link StreamFactory#getInstance(InputStream, Type)}.
	 *
	 * @param inputStream input stream,
	 * @param type expected type.
	 * @return stream instance accordingly requested type.
	 * @throws IOException if newly stream creation fails.
	 * @throws IllegalArgumentException if there requested type is not supported.
	 */
	@Override
	public Object read(InputStream inputStream, Type type) throws IOException {
		Closeable closeable = StreamFactory.getInstance(inputStream, type);
		threadLocal.set(closeable);
		return closeable;
	}

	/** Close closeable object from current thread storage then remove the storage. */
	@Override
	public void clean() {
		Files.close(threadLocal.get());
		threadLocal.remove();
	}
}


package js.container;

import java.util.HashMap;
import java.util.Map;

/**
 * Scope factory for application level singletons. Application scope factory has an {@link #instancesPool} and attempt to
 * retrieve managed instance from it via {@link #getInstance(InstanceKey)}; instances pool is updated by
 * {@link #persistInstance(InstanceKey, Object)}. Both uses the key provided managed instance key.
 *
 * @author Iulian Rotaru
 * @version final
 */
final class ApplicationScopeFactory implements ScopeFactory {
	/**
	 * Managed instances pool for managed classes with application scope. Note that this cache has application scope only if
	 * this factory has; anyway, container takes care to create a single instance of any scope factory, including this.
	 */
	private Map<InstanceKey, Object> instancesPool = new HashMap<>();

	@Override
	public InstanceScope getInstanceScope() {
		return InstanceScope.APPLICATION;
	}

	/**
	 * Retrieve instance bound to given managed instance key or null if none found. Uses instanceKey argument to
	 * get instance from {@link #instancesPool}. Managed instance key argument should be not null.
	 *
	 * @param instanceKey managed instance key.
	 * @return managed instance or null.
	 */
	@Override
	public Object getInstance(InstanceKey instanceKey) {
		// at this point managed instance key is guaranteed to be non null
		return instancesPool.get(instanceKey);
	}

	/**
	 * Persist instance bound to given managed instance key. This method simply uses provided instanceKey argument
	 * to add instance to {@link #instancesPool}. Both arguments should to be not null.
	 *
	 * @param instanceKey managed instance key,
	 * @param instance managed instance.
	 */
	@Override
	public void persistInstance(InstanceKey instanceKey, Object instance) {
		// at this point managed class and instance are guaranteed to be non null
		instancesPool.put(instanceKey, instance);
	}

	/** Clear {@link #instancesPool}. */
	@Override
	public void clear() {
		instancesPool.clear();
	}
}


package net.typedrest.vaadin.views;

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import net.typedrest.*;
import net.typedrest.vaadin.events.ElementEvent;
import net.typedrest.vaadin.forms.AutoEntityLister;
import net.typedrest.vaadin.forms.EntityLister;
import com.vaadin.ui.*;
import com.vaadin.ui.themes.ValoTheme;
import java.io.FileNotFoundException;
import java.io.IOException;

/**
 * Base class for building view components operating on an
 * {@link CollectionEndpoint}.
 *
 * @param <TEntity> The type of entity the TEndpoint represents.
 * @param <TEndpoint> The specific type of {@link CollectionEndpoint} to operate
 * on.
 * @param <TElementEndpoint> The specific type of {@link ElementEndpoint} the
 * TEndpoint provides for individual TEntitys.
 */
public abstract class AbstractCollectionView<TEntity, TEndpoint extends GenericCollectionEndpoint<TEntity, TElementEndpoint>, TElementEndpoint extends ElementEndpoint<TEntity>>
        extends AbstractEndpointView<TEndpoint> {

    protected final EntityLister<TEntity> lister;

    private final Button createButton = new Button("Create", x -> create()) {
        {
            addStyleName(ValoTheme.BUTTON_FRIENDLY);
        }
    };
    protected final Button refreshButton = new Button("Refresh", x -> refresh());
    protected final HorizontalLayout buttonsLayout = new HorizontalLayout(createButton, refreshButton) {
        {
            setSpacing(true);
        }
    };

    protected final VerticalLayout masterLayout;

    /**
     * Creates a new REST collection component.
     *
     * @param endpoint The REST endpoint this component operates on.
     * @param eventBus Used to send event between components.
     * @param lister A component for listing entity instances.
     */
    @SuppressWarnings("OverridableMethodCallInConstructor") // False positive due to lambda
    protected AbstractCollectionView(TEndpoint endpoint, EventBus eventBus, EntityLister<TEntity> lister) {
        super(endpoint, eventBus);
        setCaption(endpoint.getEntityType().getSimpleName() + "s");

        this.lister = lister;
        lister.setSizeFull();
        lister.addEntityClickListener(x -> {
            if (openElementEnabled) {
                onOpenElement(x);
            }
        });

        masterLayout = new VerticalLayout(lister, buttonsLayout);
        masterLayout.setExpandRatio(lister, 1);
        masterLayout.setComponentAlignment(buttonsLayout, Alignment.MIDDLE_RIGHT);
        masterLayout.setMargin(true);
        masterLayout.setSpacing(true);
        masterLayout.setSizeFull();
        setCompositionRoot(masterLayout);
    }

    /**
     * Creates a new REST collection component.
     *
     * @param endpoint The REST endpoint this component operates on.
     * @param eventBus Used to send event between components.
     */
    protected AbstractCollectionView(TEndpoint endpoint, EventBus eventBus) {
        this(endpoint, eventBus, new AutoEntityLister<>(endpoint.getEntityType()));
    }

    @Override
    protected void onLoad()
            throws IOException, IllegalArgumentException, IllegalAccessException, FileNotFoundException, IllegalStateException {
        lister.setEntities(endpoint.readAll());

        endpoint.isCreateAllowed().ifPresent(this::setCreateEnabled);
    }

    private boolean openElementEnabled = true;

    /**
     * Controls whether selecting individual elements opens an edit view.
     *
     * @param val Turns the feature on or off.
     */
    public void setOpenElementEnabled(boolean val) {
        openElementEnabled = val;
    }

    /**
     * Handler for opening an existing element in the collection.
     *
     * @param entity The entity that was clicked.
     */
    protected void onOpenElement(TEntity entity) {
        open(buildElementView(endpoint.get(entity)));
    }

    /**
     * Builds an {@link AbstractEndpointView} for viewing or editing an existing
     * TEntity represented by the given element endpoint.
     *
     * @param elementEndpoint The endpoint representing the entity to be
     * updated.
     * @return The new component.
     */
    protected abstract ViewComponent buildElementView(TElementEndpoint elementEndpoint);

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

    /**
     * Opens a view for creating a new element in the collection.
     */
    public void create() {
        open(buildCreateElementView());
    }

    /**
     * Builds an {@link AbstractEndpointView} for creating a new
     * TEntity in the collection endpoint.
     *
     * @return The new component.
     */
    protected abstract ViewComponent buildCreateElementView();

    // Refresh when child elements are created or updated
    @Subscribe
    public void handle(ElementEvent<TEntity> message) {
        if (message.getEndpoint().getEntityType() == this.endpoint.getEntityType()) {
            refresh();
        }
    }
}


/*
 * 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.log4j;

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

import java.util.List;

/**
 * This fixture is used to start captures of log4j logger.
 * To capture the output, the logger and the specific appender must be
 * provided. This means, that the appender must have a name.
 *

 * Example to monitor the output of the appender "R" of the root logger,
 * to monitor the output the output of the appender "stdout" of the
 * org.example.myclass and do clear the cached log entries of "stderr":
 *

 *
fitgoodies.log4j.SetupFixture

 *
monitorRoot	R

 *
monitor	org.example.myclass	stdout

 *
clear	org.example.myclass	stderr

 *

 *

 * And to stop monitoring the appender "stderr" of the root logger
 *

 *
fitgoodies.log4j.SetupFixture

 *
clear	org.example.myclass	stderr

 *

 */
public class SetupFixture extends Fixture {
	private final LoggerProvider loggerProvider;

	/**
	 * Creates a new SetupFixture which uses {@code provider} to get
	 * loggers. This method is mainly used for testing.
	 *
	 * @param provider provider to get logger instances
	 */
	public SetupFixture(LoggerProvider provider) {
		loggerProvider = provider;
	}

	/**
	 * Create a new SetupFixutre which captures log4j loggers.
	 */
	public SetupFixture() {
		this(new LoggerProvider());
	}

	/**
	 * Processes the content of {@code cells}.
	 *
	 * @param cells cells to process
	 */
	@Override
	protected void doCells(List<FitCell> cells) {
		String name = cells.get(0).getFitValue();

		processRowWithCommand(cells, name);
	}

	private void processRowWithCommand(List<FitCell> cells, String name) {
		if ("monitorRoot".equalsIgnoreCase(name)) {
			processRowWithMonitorRoot(cells);
		} else if ("monitor".equalsIgnoreCase(name)) {
			processRowWithMonitor(cells);
		} else if ("clear".equalsIgnoreCase(name)) {
			processRowWithClear(cells);
		}
	}

	private void processRowWithClear(List<FitCell> cells) {
		String className = cells.get(1).getFitValue();
		String appenderName = cells.get(2).getFitValue();

		LogHelper helper = DependencyManager.getOrCreate(LogHelper.class);
		helper.clear(loggerProvider.getLogger(className), appenderName);
	}

	private void processRowWithMonitor(List<FitCell> cells) {
		String className = cells.get(1).getFitValue();
		String appenderName = cells.get(2).getFitValue();

		addMonitor(className, appenderName);
	}

	private void processRowWithMonitorRoot(List<FitCell> cells) {
		String appenderName = cells.get(1).getFitValue();
		addRootMonitor(appenderName);
	}

	private void addRootMonitor(String appenderName) {
		LogHelper helper = DependencyManager.getOrCreate(LogHelper.class);
		helper.addCaptureToLogger(loggerProvider.getRootLogger(),
				appenderName);
	}

	private void addMonitor(String className, String appenderName) {
		LogHelper helper = DependencyManager.getOrCreate(LogHelper.class);
		helper.addCaptureToLogger(
				loggerProvider.getLogger(className), appenderName);
	}
}


package net.typedrest;

import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;
import static java.util.Arrays.stream;
import lombok.SneakyThrows;
import static org.apache.commons.lang3.reflect.FieldUtils.getField;

/**
 * Utility methods for Java beans (classes with getters and setters).
 */
public final class BeanUtils {

    private BeanUtils() {
    }

    /**
     * Lists all properties on a bean type. Ensures properties annotated with
     * {@link Id} or called "name" are always listed first.
     *
     * @param beanType The type of bean to check for properties.
     * @return A list of properties.
     */
    @SneakyThrows
    public static List<PropertyDescriptor> getProperties(Class<?> beanType) {
        LinkedList<PropertyDescriptor> properties = new LinkedList<>();
        for (PropertyDescriptor property : Introspector.getBeanInfo(beanType).getPropertyDescriptors()) {
            if (getAnnotation(beanType, property, Id.class).isPresent() || property.getName().equals("name")) {
                properties.addFirst(property);
            } else {
                properties.add(property);
            }
        }
        return properties;
    }

    /**
     * Lists all properties on a bean type that have a specific annotation on
     * their getter or backing field.
     *
     * @param <TAnnotation> The annotation type to look for.
     * @param beanType The type of bean to check for properties.
     * @param annotationType The annotation type to look for.
     * @return A list of matching properties.
     */
    public static <TAnnotation extends Annotation> List<PropertyDescriptor> getPropertiesWithAnnotation(Class<?> beanType, Class<TAnnotation> annotationType) {
        LinkedList<PropertyDescriptor> result = new LinkedList<>();
        getProperties(beanType).forEach(property -> {
            if (property.getReadMethod() != null && property.getReadMethod().getAnnotation(annotationType) != null
                    || isFieldAnnotated(beanType, property.getName(), annotationType)) {
                result.add(property);
            }
        });
        return result;
    }

    /**
     * Lists all readable and writable properties on a bean type that do not
     * have a specific annotation on their getter or backing field.
     *
     * @param <TAnnotation> The annotation type to look for.
     * @param beanType The type of bean to check for properties.
     * @param annotationType The annotation type to look for.
     * @return A list of matching properties.
     */
    public static <TAnnotation extends Annotation> List<PropertyDescriptor> getPropertiesWithoutAnnotation(Class<?> beanType, Class<TAnnotation> annotationType) {
        LinkedList<PropertyDescriptor> result = new LinkedList<>();
        getProperties(beanType).forEach(property -> {
            if ((property.getReadMethod() == null || property.getReadMethod().getAnnotation(annotationType) == null)
                    && !isFieldAnnotated(beanType, property.getName(), annotationType)) {
                result.add(property);
            }
        });
        return result;
    }

    private static <TAnnotation extends Annotation> boolean isFieldAnnotated(Class<?> beanType, String fieldName, Class<TAnnotation> annotationType) {
        Field field = getField(beanType, fieldName, true);
        return (field != null) && (field.getAnnotation(annotationType) != null);
    }

    /**
     * Returns an annotation of a specific type on a property's getter or its
     * backing field.
     *
     * @param <TAnnotation> The type of annotation to look for.
     * @param beanType The type of bean the property is declared on.
     * @param property The property to check for the annotation.
     * @param annotationType The type of annotation to look for.
     * @return The annotation if present.
     */
    public static <TAnnotation extends Annotation> Optional<TAnnotation> getAnnotation(Class<?> beanType, PropertyDescriptor property, Class<TAnnotation> annotationType) {
        Optional<TAnnotation> annotation = stream(property.getReadMethod().getAnnotationsByType(annotationType)).findAny();
        return annotation.isPresent()
                ? annotation
                : getAnnotationOnField(beanType, property.getName(), annotationType);
    }

    private static <TAnnotation extends Annotation> Optional<TAnnotation> getAnnotationOnField(Class<?> beanType, String fieldName, Class<TAnnotation> annotationType) {
        Field field = getField(beanType, fieldName, true);
        TAnnotation annotation = (field == null) ? null : field.getAnnotation(annotationType);
        return Optional.ofNullable(annotation);
    }
}


/*
 * 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 de.cologneintelligence.fitgoodies.ActionFixture;
import de.cologneintelligence.fitgoodies.util.DependencyManager;

import java.io.File;

/**
 * The file fixture is used to select files via HTML:
 *

 *
fitgoodies.file.FileFixture

 *
directory	/my/dir

 *
pattern	.*\.txt

 *
encoding	utf-8

 *

 *

 * The fixture sets the values in {@link FileFixtureHelper}.
 *
 * @see FileFixtureHelper FileFixtureHelper
 */
public class FileFixture extends ActionFixture {
	/**
	 * Sets the filename pattern to {@code pattern}.
	 *
	 * @param pattern pattern to use
	 */
	public void pattern(final String pattern) {
		FileFixtureHelper helper = DependencyManager.getOrCreate(FileFixtureHelper.class);
		helper.setPattern(pattern);
	}

	/**
	 * Calls {@link #pattern(String)}, using the next cell as its parameter.
	 *
	 * @throws Exception propagated to fit
	 */
	public void pattern() 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();
	}

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

	/**
	 * Sets the directory to {@code directory}.
	 *
	 * @param directory directory to use
	 */
	public void directory(final String directory) {
		FileFixtureHelper helper = DependencyManager.getOrCreate(FileFixtureHelper.class);
		helper.setDirectory(new File(directory));
	}

	/**
	 * Sets the encoding to {@code encoding}.
	 *
	 * @param encoding encoding to use
	 */
	public void encoding(final String encoding) {
		FileFixtureHelper helper = DependencyManager.getOrCreate(FileFixtureHelper.class);
		helper.setEncoding(encoding);
	}
}


package js.servlet;

import java.io.File;
import java.io.FileNotFoundException;

import js.lang.BugError;
import js.lang.Config;
import js.lang.ConfigBuilder;
import js.lang.ConfigException;
import js.log.LogFactory;

/**
 * Server global state and applications logger initialization. This class assumes standard Tomcat deployment. System property
 * {@link #SERVER_BASE} should be defined and point to web server base directory.
 *

 * This class also takes care to initialize applications logger. If logs directory or logging configuration file not found
 * applications logger is forced to console.
 *

 * Warning: If server base directory not found web server start-up fails.
 *
 * @author Iulian Rotaru
 * @version final
 */
final class Server {
	/** System property storing server base directory. */
	private static final String SERVER_BASE = "catalina.base";

	/** Applications working directory relative to catalina base. */
	private static final String APP_WORK = "work/Applications";

	/** Web server logs directory. */
	private static final String LOGS_DIR = "logs";

	/** Web server configuration directory. */
	private static final String CONF_DIR = "conf";

	/** Applications logger configuration file. */
	private static final String LOG_XML = "log.xml";

	/** Server base directory, absolute path. */
	private final File serverBase;

	/** Absolute path to applications working directory. This is location where applications private directories are created. */
	private final File appWorkDir;

	/** Initialize server global state and applications logger. */
	public Server() {
		String serverBaseProperty = System.getProperty(SERVER_BASE);
		if (serverBaseProperty == null) {
			throw new BugError(log("Invalid environment: missing ${%s} system property. Server startup abort.", SERVER_BASE));
		}
		serverBase = new File(serverBaseProperty);
		if (!serverBase.exists()) {
			throw new BugError(log("Invalid environment: bad ${%s} system property. Web server directory |%s| does not exist. Server startup abort.", SERVER_BASE, serverBase));
		}

		appWorkDir = new File(serverBase, APP_WORK);
		appWorkDir.mkdirs();

		File logsDir = new File(serverBase, LOGS_DIR);
		if (!logsDir.exists()) {
			log("Missing logs directory |%s|. Force logger to console.", logsDir);
			return;
		}
		// system property 'logs' is used by log4j, e.g. RollingFileAppender
		System.setProperty("logs", logsDir.getAbsolutePath());

		File confDir = new File(serverBase, CONF_DIR);
		if (!confDir.isDirectory()) {
			log("Missing web server configuration directory |%s|. Force logger to console.", logsDir);
			return;
		}

		File logDescriptor = new File(confDir, LOG_XML);
		Config config = null;
		try {
			ConfigBuilder builder = new ConfigBuilder(logDescriptor);
			config = builder.build();
		} catch (FileNotFoundException unused) {
			log("Logger configuration file |%s| not found. Force logger to console.", logDescriptor);
			return;
		} catch (ConfigException e) {
			throw new BugError(log("Fail to load logger configuration from |%s|. Server fatal stop. Correct logger configuration or remove it to force logger to console.", logDescriptor.getAbsoluteFile()));
		}
		LogFactory.config(config);
	}

	/**
	 * Get application private directory. Application private directory is where application stores its private files. Note that
	 * privateness is rather a good practice recommendation and is not enforced by some system rights.
	 *
	 * @param appName application name.
	 * @return application working directory.
	 */
	public File getAppDir(String appName) {
		return new File(appWorkDir, appName);
	}

	// --------------------------------------------------------------------------------------------
	// UITILITY METHODS

	/**
	 * Log formatted message to Java logger since framework logger is not yet initialized.
	 *
	 * @param message message with optional formatting elements as supported by {@link String#format(String, Object...)},
	 * @param args optional arguments.
	 * @return formatted message.
	 */
	private static String log(String message, Object... args) {
		message = String.format(message, args);
		java.util.logging.Logger.getLogger(Server.class.getCanonicalName()).log(java.util.logging.Level.SEVERE, message);
		return message;
	}
}


package uk.bl.wa.whois;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;

import org.jruby.embed.EvalFailedException;
import org.jruby.embed.LocalContextScope;
import org.jruby.embed.ScriptingContainer;

import uk.bl.wa.whois.exceptions.ServerNotFoundException;
import uk.bl.wa.whois.exceptions.WebInterfaceErrorException;
import uk.bl.wa.whois.record.WhoisResult;

public class JRubyWhois {

    ScriptingContainer container = new ScriptingContainer(
            LocalContextScope.CONCURRENT);

    public JRubyWhois() {
        this(false);
    }

    /**
     * @param debug Set to false to disable ruby stderr/stdout
     */
    public JRubyWhois(boolean debug) {
        if (!debug) {
            PrintStream printStream = new PrintStream(new OutputStream() {
                @Override
                public void write(int b) throws IOException {
                }
            });
            container.setError(printStream);
            container.setOutput(printStream);
        }
    }

    /**
     *
     * Uses the Ruby Whois gem to perform a whois lookup.
     *
     * @param domain
     *            domain name to lookup
     * @return
     */
    public WhoisResult lookup(String domain) {
        return lookup(domain, 30);
    }

    /**
     * Uses the Ruby Whois gem to perform a whois lookup
     *
     * @param domain
     *            domain name to lookup
     * @param timeout
     *            timeout in seconds
     * @return
     */
    public WhoisResult lookup(String domain, int timeout) {
        container.put("domain", domain);
        container.put("timeout_param", timeout);
        try {
            return (WhoisResult) container.runScriptlet(
                    JRubyWhois.class.getResourceAsStream("jruby-whois.rb"),
                    "jruby-whois.rb");
        } catch (EvalFailedException e) {
            if (e.getMessage().startsWith("(ServerNotFound)")) {
                throw new ServerNotFoundException(e);
            }
            if (e.getMessage().startsWith("(WebInterfaceError")) {
                throw new WebInterfaceErrorException(e);
            }
            throw e;
        }
    }

    /**
     * Check if Ruby Whois gem has a parser for a specific registrar
     *
     * @param whoisHost
     *            whois server to check
     * @return
     */
    public boolean hasParserForWhoisHost(String whoisHost) {
        container.put("host", whoisHost);
        return (Boolean) container.runScriptlet(
                JRubyWhois.class.getResourceAsStream("jruby-has-parser.rb"),
                "jruby-has-parser.rb");
    }
}


package js.net;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import js.container.AuthorizationException;
import js.container.ContainerSPI;
import js.container.ManagedClassSPI;
import js.container.ManagedMethodSPI;
import js.http.ContentType;
import js.http.Resource;
import js.http.encoder.ArgumentsReader;
import js.http.encoder.ArgumentsReaderFactory;
import js.http.encoder.ServerEncoders;
import js.http.encoder.ValueWriter;
import js.http.encoder.ValueWriterFactory;
import js.log.Log;
import js.log.LogFactory;
import js.servlet.AppServlet;
import js.servlet.RequestContext;
import js.util.Classes;
import js.util.Types;

/**
 * Application servlet implementation for HTTP-RMI requests. This servlet invokes remotely accessible methods for services
 * requested by external clients, including XHR requests from browsers.
 *

 * HTTP-RMI servlet should be declared into deployment descriptor. Usually HTTP-RMI servlet is mapped to .rmi
 * extension but there is no formal requirements for that. In fact request path pattern defines extension as optional.
 *
 *

 * 	<servlet>
 * 		<servlet-name>rmi-servlet</servlet-name>
 * 		<servlet-class>js.net.HttpRmiServlet</servlet-class>
 * 		<load-on-startup>1</load-on-startup>
 * 	</servlet>
 * 	...
 * 	<servlet-mapping>
 * 		<servlet-name>rmi-servlet</servlet-name>
 * 		<url-pattern>*.rmi</url-pattern>
 * 	</servlet-mapping>
 *

 *

 * Request path pattern for HTTP-RMI. One may notice that request path is a method qualified name using slash as separator.
 * Request path syntax supports extension and URL query parameters but this servlet does not use them.
 *
 *

 *    request-path = "/" qualified-class "/" method ["." extension] ["?" query-parameters]
 *
 *    qualified-class = package *("/" package) "/" class ["/" inner-class]
 *    package = LCHAR *CHAR
 *    class = UCHAR *CHAR
 *    inner-class = class
 *    method = LCHAR *CHAR
 *
 *    extension = +CHAR
 *
 *    query-parameters = [query-parameter ["&" query-parameter]]
 *    query-parameter = query-name ["=" query-value]
 *    query-name = +CHAR
 *    query-value = +CHAR
 *
 *    CHAR = < any character less "/", ".", "?" >
 *    LCHAR = < lower case ASCII character [a-z] >
 *    UCHAR = < upper case ASCII character [A-Z] >
 *

 *

 * Execution exceptions, other that {@link IOException} are send back to client via
 * {@link AppServlet#sendError(RequestContext, Throwable)}, notable next ones:
 *

 *
ClassNotFoundException if request path syntax is invalid or if there is no remotely accessible managed class with
 * requested interface,
 *
NoSuchMethodException if requested method does not exist or is not remotely accessible,
 *
IllegalArgumentException argument encoded into HTTP request body does not match method formal parameters list.
 *

 *

 * If method about be invoked is private and security context is not authorized this servlet uses
 * {@link AppServlet#sendUnauthorized(RequestContext)} to signal to client that authentication is required.
 *
 * @author Iulian Rotaru
 * @version final
 */
public final class HttpRmiServlet extends AppServlet {
	/** Java serialization version. */
	private static final long serialVersionUID = -7483018112800298638L;

	/** Class logger. */
	private static final Log log = LogFactory.getLog(HttpRmiServlet.class);

	/** Request path pattern for HTTP-RMI. See class description for supported syntax. */
	private static final Pattern REQUEST_PATH_PATTERN = Pattern.compile("^" + //
			"(\\/[a-z][a-z0-9]*(?:\\/[a-z][a-z0-9]*)*(?:\\/[A-Z][a-zA-Z0-9_]*)+)" + // qualified (inner)class name
			"\\/" + // path separator
			"([a-z][a-zA-Z0-9_]*)" + // method name
			"(?:\\..+)?" + // extension
			"(?:\\?(?:[^=]+=[^=]+)(?:&[^=]+=[^=]+)*)?" + // query parameters
			"$");

	/**
	 * Factory for invocation arguments readers. Create instances to read invocation arguments from HTTP request, accordingly
	 * request content type.
	 */
	private final ArgumentsReaderFactory argumentsReaderFactory;

	/** Factory for return value writers. Create instances to serialize method return value to HTTP response. */
	private final ValueWriterFactory valueWriterFactory;

	/** Initialize invocation arguments reader and return value writer factories. */
	public HttpRmiServlet() {
		log.trace("RmiServlet()");
		// both factories are implemented by the same server encoders
		argumentsReaderFactory = ServerEncoders.getInstance();
		valueWriterFactory = ServerEncoders.getInstance();
	}

	/**
	 * HTTP-RMI request service. This is the implementation of the
	 * {@link AppServlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse)} abstract method. It locates
	 * remote managed method addressed by request path, deserialize actual parameters from HTTP request, reflexively invoke the
	 * method and serialize method returned value to HTTP response.
	 *

	 * Actual parameters are transported into HTTP request body and are encoded accordingly Content-Type request
	 * header; for supported parameters encodings please see
	 * {@link ServerEncoders#getArgumentsReader(HttpServletRequest, Type[])} factory method. On its side, returned value is
	 * transported into HTTP response body too and is encoded accordingly its type - see
	 * {@link ServerEncoders#getValueWriter(ContentType)} for supported encodings for returned value.
	 *
	 * @param context HTTP request context.
	 * @throws IOException if HTTP request reading fails for any reason.
	 */
	@Override
	public void handleRequest(RequestContext context) throws IOException {
		HttpServletRequest httpRequest = context.getRequest();
		HttpServletResponse httpResponse = context.getResponse();

		Matcher matcher = REQUEST_PATH_PATTERN.matcher(context.getRequestPath());
		if (!matcher.find()) {
			sendBadRequest(context);
			return;
		}
		String interfaceName = className(matcher.group(1));
		String methodName = matcher.group(2);

		ManagedMethodSPI managedMethod = null;
		ArgumentsReader argumentsReader = null;
		Object value = null;

		try {
			ManagedClassSPI managedClass = getManagedClass(container, interfaceName, httpRequest.getRequestURI());
			managedMethod = getManagedMethod(managedClass, methodName, httpRequest.getRequestURI());

			final Type[] formalParameters = managedMethod.getParameterTypes();
			argumentsReader = argumentsReaderFactory.getArgumentsReader(httpRequest, formalParameters);
			Object[] arguments = argumentsReader.read(httpRequest, formalParameters);

			Object instance = container.getInstance(managedClass);
			value = managedMethod.invoke(instance, arguments);
		} catch (AuthorizationException e) {
			sendUnauthorized(context);
			return;
		} catch (Throwable t) {
			// all exception, including class not found, no such method and illegal argument are send back to client as they are
			sendError(context, t);
			return;
		} finally {
			if (argumentsReader != null) {
				argumentsReader.clean();
			}
		}

		httpResponse.setCharacterEncoding("UTF-8");
		if (managedMethod.isVoid()) {
			httpResponse.setStatus(HttpServletResponse.SC_NO_CONTENT);
			return;
		}

		ContentType contentType = valueWriterFactory.getContentTypeForValue(value);
		httpResponse.setStatus(HttpServletResponse.SC_OK);
		httpResponse.setContentType(contentType.getValue());

		ValueWriter valueWriter = valueWriterFactory.getValueWriter(contentType);
		valueWriter.write(httpResponse, value);
	}

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

	/**
	 * Get remotely accessible managed class registered to a certain interface class.
	 *
	 * @param container parent container,
	 * @param interfaceName name of the interface class identifying requested managed class,
	 * @param requestURI request URI for logging.
	 * @return managed class, never null.
	 * @throws ClassNotFoundException if interface class not found on run-time class path, managed class not defined or is not
	 *             remotely accessible.
	 */
	private static ManagedClassSPI getManagedClass(ContainerSPI container, String interfaceName, String requestURI) throws ClassNotFoundException {
		Class<?> interfaceClass = Classes.forOptionalName(interfaceName);
		if (interfaceClass == null) {
			log.error("HTTP-RMI request for not existing class |%s|.", interfaceName);
			throw new ClassNotFoundException(requestURI);
		}
		ManagedClassSPI managedClass = container.getManagedClass(interfaceClass);
		if (managedClass == null) {
			log.error("HTTP-RMI request for not existing managed class |%s|.", interfaceName);
			throw new ClassNotFoundException(requestURI);
		}
		if (!managedClass.isRemotelyAccessible()) {
			log.error("HTTP-RMI request for local managed class |%s|. See @Remote annotation.", interfaceName);
			throw new ClassNotFoundException(requestURI);
		}
		return managedClass;
	}

	/**
	 * Get managed method that is remotely accessible and has requested name.
	 *
	 * @param managedClass managed class where method is supposed to be declared,
	 * @param methodName method name,
	 * @param requestURI request URI for logging.
	 * @return managed method, never null.
	 * @throws NoSuchMethodException if managed class has not any method with requested name, managed method was found but is
	 *             not remotely accessible or it returns a {@link Resource}.
	 */
	private static ManagedMethodSPI getManagedMethod(ManagedClassSPI managedClass, String methodName, String requestURI) throws NoSuchMethodException {
		ManagedMethodSPI managedMethod = managedClass.getNetMethod(methodName);
		if (managedMethod == null) {
			log.error("HTTP-RMI request for not existing managed method |%s#%s|.", managedClass.getInterfaceClass().getName(), methodName);
			throw new NoSuchMethodException(requestURI);
		}
		if (!managedMethod.isRemotelyAccessible()) {
			log.error("HTTP-RMI request for local managed method |%s#%s|. See @Remote annotation.", managedClass.getInterfaceClass().getName(), methodName);
			throw new NoSuchMethodException(requestURI);
		}
		if (Types.isKindOf(managedMethod.getReturnType(), Resource.class)) {
			log.error("HTTP-RMI request for managed method |%s#%s| returning a resource.", managedClass.getInterfaceClass().getName(), methodName);
			throw new NoSuchMethodException(requestURI);
		}
		return managedMethod;
	}

	/**
	 * Extract qualified class name, including inner classes, from class path part of the request path. Class path parameter is
	 * the class name but with slash as separator, e.g. /sixqs/site/controller/ParticipantController. This helper
	 * handles inner classes using standard notation with '$' separator; for example
	 * /js/test/net/RmiController/Query is converted to js.test.net.RmiController$Query.
	 *

	 * Class nesting is not restricted to a single level. For example /js/test/net/RmiController/Query/Item is
	 * converted to js.test.net.RmiController$Query$Item.
	 *

	 * It is expected that class path argument to be well formed. If class path argument is not valid this method behavior is
	 * not defined.
	 *
	 * @param classPath qualified class name using slash as separator and with leading path separator.
	 * @return qualified class name using dollar notation for inner classes.
	 */
	private static String className(String classPath) {
		StringBuilder className = new StringBuilder();
		char separator = '.';
		char c = classPath.charAt(1);
		// i = 1 to skip leading path separator
		for (int i = 1;;) {
			if (c == '/') {
				c = separator;
			}
			className.append(c);

			if (++i == classPath.length()) {
				break;
			}

			c = classPath.charAt(i);
			// after first class detected change separator to dollar since rest are inner classes
			// this solution copes well with not restricted inner level
			if (Character.isUpperCase(c)) {
				separator = '$';
			}
		}
		return className.toString();
	}
}


/*
 * 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.log4j;

import de.cologneintelligence.fitgoodies.Validator;
import de.cologneintelligence.fitgoodies.htmlparser.FitCell;
import de.cologneintelligence.fitgoodies.util.FitUtils;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.ThrowableInformation;

import java.util.Map;

/**
 * Analyzes log events using an {@link AbstractLoggingEventMatcher}.
 */
public class LogEventAnalyzer {
	private final Validator validator;
	private final FitCell cell;
	private final LoggingEvent[] events;

	/**
	 * Creates a new analyzer.
	 *
	 * @param validator     validator for cell
	 * @param conditionCell cell which contains the reference value
	 * @param events        log events to process
	 */
	public LogEventAnalyzer(Validator validator, FitCell conditionCell, LoggingEvent[] events) {
		this.validator = validator;
		this.cell = conditionCell;
		this.events = events;
	}

	/**
	 * Checks whether the log messages contain the expected exception.
	 *
	 * @param parameters parameters to filter the processing
	 *                   (see {@link AbstractLoggingEventMatcher}
	 */
	public void processNotContainsException(Map<String, String> parameters) {
		LoggingEvent match = getMessageWithException(parameters);

		if (match == null) {
			cell.right();
		} else {
			cell.wrong(match.getThrowableInformation().getThrowableStrRep()[0]);
		}
	}

	/**
	 * Checks whether the log messages do not contain the expected exception.
	 *
	 * @param parameters parameters to filter the processing
	 *                   (see {@link AbstractLoggingEventMatcher}
	 */
	public void processContainsException(Map<String, String> parameters) {
		LoggingEvent match = getMessageWithException(parameters);

		if (match == null) {
			cell.wrong();
		} else {
			cell.right();
			appendActualAndExpected(match.getThrowableInformation().getThrowableStrRep()[0]);
		}
	}

	private String getLowerCaseCheckExpression() {
		String resolvedContent = validator.preProcess(cell);
		cell.setDisplayValue(FitUtils.escape(resolvedContent));
		return resolvedContent.toLowerCase();
	}

	private LoggingEvent getMessageWithException(Map<String, String> parameters) {
		final String lowerCaseCheckExpression = getLowerCaseCheckExpression();

		return getMatchingEvent(new AbstractLoggingEventMatcher() {
			@Override
			boolean matches(LoggingEvent event) {
				ThrowableInformation errorInfo = event.getThrowableInformation();
				if (errorInfo == null) {
					return false;
				}

				return errorInfo.getThrowableStrRep()[0].toLowerCase()
						.contains(lowerCaseCheckExpression);
			}
		}, parameters);
	}

	/**
	 * Checks whether the log messages contain the expected text.
	 *
	 * @param parameters parameters to filter the processing
	 *                   (see {@link AbstractLoggingEventMatcher}
	 */
	public void processContains(Map<String, String> parameters) {
		LoggingEvent match = getMessageWithString(parameters);

		if (match == null) {
			cell.wrong();
		} else {
			cell.right();
			appendActualAndExpected(match.getMessage().toString());
		}
	}

	/**
	 * Checks whether the log messages do not contain the expected text.
	 *
	 * @param parameters parameters to filter the processing
	 *                   (see {@link AbstractLoggingEventMatcher}
	 */
	public void processNotContains(Map<String, String> parameters) {
		LoggingEvent match = getMessageWithString(parameters);

		if (match == null) {
            cell.right();
		} else {
			cell.wrong(match.getMessage().toString());

		}
	}

	private LoggingEvent getMessageWithString(Map<String, String> parameters) {
		final String checkExpression = getLowerCaseCheckExpression();
		return getMatchingEvent(new AbstractLoggingEventMatcher() {
			@Override
			boolean matches(LoggingEvent arg0) {
				return arg0.getRenderedMessage().toLowerCase().contains(checkExpression);
			}
		}, parameters);
	}

	private LoggingEvent getMatchingEvent(AbstractLoggingEventMatcher matcher,
	                                      Map<String, String> parameters) {
		return matcher.getFirstMatchingEvent(events, parameters);
	}

	private void appendActualAndExpected(String actual) {
		cell.info("(expected)");
		cell.rawInfo("<hr/>");
		cell.info(actual);
		cell.info("(actual)");
	}
}


/**
 * 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.Map;

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 javax.xml.bind.annotation.XmlType;

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

/**
 * Container for a key and a value combination.
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(propOrder = { "value", "key" })
@XmlRootElement(name = "argument")
public final class Argument implements Serializable, Comparable<Argument> {

    private static final long serialVersionUID = 1L;

    @TrimmedNotEmpty
    @XmlAttribute
    private String key;

    @TrimmedNotEmpty
    @XmlAttribute
    private String value;

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

    /**
     * Constructor with key and value.
     *
     * @param key
     *            Key - Cannot be NULL.
     * @param value
     *            Value - Cannot be NULL.
     */
    public Argument(final String key, final String value) {
        super();
        this.key = key;
        this.value = value;
    }

    /**
     * Returns the key.
     *
     * @return Key - Never NULL.
     */
    public final String getKey() {
        return key;
    }

    /**
     * Returns the value.
     *
     * @return Value - Never NULL.
     */
    public final String getValue() {
        return value;
    }

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

    @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 Argument other = (Argument) obj;
        return key.equals(other.key);
    }

    @Override
    public final int compareTo(final Argument other) {
        return key.compareTo(other.key);
    }

    @Override
    public final String toString() {
        return key + "='" + value + "'";
    }

    /**
     * Replaces variables (if defined) in the value.
     *
     * @param vars
     *            Variables to use.
     */
    public final void init(final Map<String, String> vars) {
        value = Utils4J.replaceVars(getValue(), vars);
    }

}


package js.mvc;

import java.io.IOException;
import java.io.OutputStream;

import javax.servlet.http.HttpServletResponse;

import js.http.ContentType;
import js.http.HttpHeader;

/**
 * Views abstract base class. This base class initializes common HTTP response headers and delegates actual serialization to
 * concrete implementation, see {@link #serialize(OutputStream)}. Also implementation should provide view content type via
 * {@link #getContentType()}.
 *
 * @author Iulian Rotaru
 * @version final
 */
public abstract class AbstractView implements View {
	/**
	 * Get generated stream content type.
	 *
	 * @return this view content type.
	 */
	protected abstract ContentType getContentType();

	/**
	 * Perform the actual content serialization to given output stream. Implementation has access to both view-meta and domain
	 * model instance that are both initialized before serialization execution.
	 *
	 * @param outputStream output stream to serialize content to.
	 * @throws IOException if writing to output stream fails.
	 */
	protected abstract void serialize(OutputStream outputStream) throws IOException;

	/** View meta data loaded by view manager from external configuration object. */
	protected ViewMeta meta;

	/** Model instance used to populate this view instance. Model is supplied by application and can be null. */
	protected Object model;

	/**
	 * Set meta-data for this view instance.
	 *
	 * @param meta view meat-data.
	 */
	void setMeta(ViewMeta meta) {
		this.meta = meta;
	}

	@Override
	public View setModel(Object model) {
		this.model = model;
		return this;
	}

	/**
	 * Set common HTTP response headers and delegates actual serialization to subclass. This method disables cache and set
	 * content type to value returned by subclass.
	 *
	 * @param httpResponse HTTP response to serialize view to.
	 * @throws IOException if view serialization fails for whatever reasons.
	 */
	@Override
	public void serialize(HttpServletResponse httpResponse) throws IOException {
		httpResponse.setHeader(HttpHeader.CACHE_CONTROL, HttpHeader.NO_CACHE);
		httpResponse.addHeader(HttpHeader.CACHE_CONTROL, HttpHeader.NO_STORE);
		httpResponse.setHeader(HttpHeader.PRAGMA, HttpHeader.NO_CACHE);
		httpResponse.setDateHeader(HttpHeader.EXPIRES, 0);
		httpResponse.setContentType(getContentType().getValue());

		serialize(httpResponse.getOutputStream());
	}
}


package js.servlet;

import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import js.converter.Converter;
import js.converter.ConverterException;
import js.converter.ConverterRegistry;
import js.util.Params;

/**
 * Cookies utility provide means for individual cookie handling and cookies collection iteration.
 *
 * @author Iulian Rotaru
 * @version final
 */
public final class Cookies implements Iterable<Cookie> {
	/** Reference to current HTTP response. */
	private HttpServletResponse httpResponse;

	/** Current HTTP request cookies provided by servlet. */
	private Cookie[] cookies;

	/**
	 * Create cookies utility instance and load internal cookies from HTTP request.
	 *
	 * @param httpRequest current HTTP request,
	 * @param httpResponse current HTTP response.
	 */
	public Cookies(HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
		this.httpResponse = httpResponse;
		this.cookies = httpRequest.getCookies();
	}

	/**
	 * Test if named cookie exists.
	 *
	 * @param name cookie name, not null or empty.
	 * @return true if named cookie exists.
	 * @throws IllegalArgumentException if name argument is null or empty.
	 */
	public boolean has(String name) {
		return get(name) != null;
	}

	/**
	 * Get value of the named cookie or null if cookie does not exist.
	 *
	 * @param name cookie name, not null or empty.
	 * @return cookie cookie value or null if there is no cookie with requested name.
	 * @throws IllegalArgumentException if name argument is null or empty.
	 */
	public String get(String name) {
		Params.notNullOrEmpty(name, "Cookie name");
		if (cookies == null) {
			return null;
		}
		for (Cookie cookie : cookies) {
			if (name.equals(cookie.getName())) {
				return cookie.getValue();
			}
		}
		return null;
	}

	/**
	 * Add cookie to HTTP response of the current request context. Override cookie value if already exists.
	 *
	 * @param name cookie name, not null or empty,
	 * @param value cookie value, not null or empty.
	 * @throws IllegalArgumentException if name argument is null or empty.
	 * @throws IllegalArgumentException if value argument is null or empty.
	 */
	public void add(String name, String value) {
		Params.notNullOrEmpty(name, "Cookie name");
		Params.notNull(value, "Cookie value");
		Cookie cookie = new Cookie(name, value);
		cookie.setPath("/");
		httpResponse.addCookie(cookie);
	}

	/**
	 * Convert value object to string and delegates {@link #add(String, String)}. String conversion is performed by
	 * {@link Converter} and may throw {@link ConverterException}.
	 *
	 * @param name cookie name, not null or empty,
	 * @param value cookie value, not null or empty.
	 * @throws IllegalArgumentException if name argument is null or empty.
	 * @throws IllegalArgumentException if value argument is null or empty.
	 * @throws ConverterException if value object has no converter registered or object value serialization fails.
	 */
	public void add(String name, Object value) {
		add(name, ConverterRegistry.getConverter().asString(value));
	}

	/**
	 * Remove cookie from HTTP response. If named cookie does not exist this method does nothing.
	 *
	 * @param name the name of the cookie to be removed, not null or empty.
	 * @throws IllegalArgumentException if name argument is null or empty.
	 */
	public void remove(String name) {
		Params.notNullOrEmpty(name, "Cookie name");
		if (cookies == null) {
			return;
		}
		for (Cookie cookie : cookies) {
			if (name.equals(cookie.getName())) {
				cookie.setMaxAge(0);
				cookie.setValue("");
				cookie.setPath("/");
				httpResponse.addCookie(cookie);
				break;
			}
		}
	}

	/**
	 * Get cookies iterator. Return empty iterator if not cookies on HTTP request.
	 *
	 * @return cookies iterator, possible empty.
	 */
	public Iterator<Cookie> iterator() {
		if (cookies == null) {
			return Collections.emptyIterator();
		}
		return Arrays.asList(cookies).iterator();
	}
}


package js.container;

import js.lang.BugError;
import js.lang.Config;
import js.lang.ConfigException;
import js.lang.Configurable;
import js.log.Log;
import js.log.LogFactory;

/**
 * Configure instance with configuration object provided by instance managed class. The actual instance configuration is
 * performed only if instance is {@link Configurable} and managed class has configuration object. If both conditions are
 * satisfied this instance processor executes {@link Configurable#config(Config)} on instance.
 * <p>
 * Configuration is about running application defined code that can fail. This processor catch all exceptions, including those
 * related to invalid configuration object and throw {@link BugError} since is clearly a not intended behavior.
 *
 * @author Iulian Rotaru
 * @version final
 */
final class ConfigurableInstanceProcessor implements InstanceProcessor {
	private static final Log log = LogFactory.getLog(ConfigurableInstanceProcessor.class);

	/**
	 * Configure instance with configuration object provided by instance managed class. In order to perform instance
	 * configuration, instance should implement {@link Configurable} and managed class should have configuration object, see
	 * {@link ManagedClassSPI#getConfig()}. If both conditions are satisfied this method executes
	 * {@link Configurable#config(Config)} on instance.
	 *
	 * @param managedClass managed class,
	 * @param instance instance of given managed class.
	 * @throws BugError if instance configuration fails either due to invalid configuration object or exception on configuration
	 *             user defined logic.
	 */
	@Override
	public void postProcessInstance(ManagedClassSPI managedClass, Object instance) {
		if (!(instance instanceof Configurable)) {
			return;
		}
		Config config = managedClass.getConfig();
		if (config == null) {
			if(!(instance instanceof OptionalConfigurable)) {
				return;
			}
			log.info("Default configuration for managed class |%s|.", managedClass);
		}

		try {
			((Configurable) instance).config(config);
		} catch (ConfigException e) {
			throw new BugError("Invalid configuration for managed class |%s|:\r\n\t- %s", managedClass, e);
		} catch (Throwable t) {
			throw new BugError(t);
		}
	}
}


/**
 * 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 static org.fuin.utils4j.Utils4J.replaceVars;

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.XmlAnyElement;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

import org.fuin.objects4j.vo.TrimmedNotEmpty;
import org.fuin.srcgen4j.commons.InitializableElement;
import org.fuin.srcgen4j.commons.SrcGen4JContext;
import org.fuin.utils4j.Utils4J;
import org.fuin.xmlcfg4j.AbstractElement;

/**
 * Configuration for a {@link TargetFileListProducer}.
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "target-file-list-producer")
@XmlType(propOrder = { "config", "className" })
public class TargetFileListProducerConfig extends AbstractElement
        implements InitializableElement<TargetFileListProducerConfig, ParameterizedTemplateModel> {

    @TrimmedNotEmpty
    @XmlAttribute(name = "class")
    private String className;

    @Valid
    @XmlAnyElement(lax = true)
    private Object config;

    private transient TargetFileListProducer tflProducer;

    private transient ParameterizedTemplateModel parent;

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

    /**
     * Returns the name of the class that implements {@link TargetFileListProducer}.
     *
     * @return Full qualified name.
     */
    public final String getClassName() {
        return className;
    }

    /**
     * Sets the name of the class that implements {@link TargetFileListProducer} .
     *
     * @param className
     *            Full qualified name.
     */
    public final void setClassName(final String className) {
        this.className = className;
    }

    /**
     * Returns the specific configuration for the target file list producer.
     *
     * @return Configuration.
     */
    public final Object getConfig() {
        return config;
    }

    /**
     * Sets the specific configuration for the target file list producer.
     *
     * @param config
     *            Configuration.
     */
    public final void setConfig(final Object config) {
        this.config = config;
    }

    /**
     * Returns the parent of the object.
     *
     * @return Parent.
     */
    public final ParameterizedTemplateModel getParent() {
        return parent;
    }

    /**
     * Sets the parent of the object.
     *
     * @param parent
     *            Parent.
     */
    public final void setParent(final ParameterizedTemplateModel parent) {
        this.parent = parent;
    }

    @Override
    @SuppressWarnings("unchecked")
    public final TargetFileListProducerConfig init(final SrcGen4JContext context, final ParameterizedTemplateModel parent,
            final Map<String, String> vars) {
        setParent(parent);
        inheritVariables(vars);
        setClassName(replaceVars(getClassName(), getVarMap()));
        if (config instanceof InitializableElement) {
            final InitializableElement<?, TargetFileListProducerConfig> ie;
            ie = (InitializableElement<?, TargetFileListProducerConfig>) config;
            ie.init(context, this, getVarMap());
        }
        return this;
    }

    /**
     * Returns an existing target file list producer instance or creates a new one if it's the first call to this method.
     *
     * @return TargetFileListProducer of type {@link #className}.
     */
    public final TargetFileListProducer getTargetFileListProducer() {
        if (tflProducer != null) {
            return tflProducer;
        }
        final Object obj = Utils4J.createInstance(className);
        if (!(obj instanceof TargetFileListProducer)) {
            throw new IllegalStateException(
                    "Expected class to be of type '" + TargetFileListProducer.class.getName() + "', but was: " + className);
        }
        tflProducer = (TargetFileListProducer) obj;
        return tflProducer;
    }

}