/*******************************************************************************
 *
 *   Copyright (C) 2005 Sean Russell
 *
 *   This file is part of Broccoli.
 *
 *   Broccoli 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.
 *
 *   Broccoli 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 Broccoli.  If not, see <http://www.gnu.org/licenses/>.
 *
 ******************************************************************************/

package com.hi3project.vineyard.comm.stomp.gozirraws;

import java.util.*;

/**
 * A Stomp messaging implementation.
 *
 * Messages are handled in one of two ways.  If subscribe was called with
 * a listener, then incoming messages are delivered to all listeners
 * of that channel, and the message is deleted from the queue.  If no
 * listener was provided for that channel, then messages are placed in
 * a queue and can be retrieved with getNext().  In all cases, when
 * messages are retrieved, they are deleted from the queue.
 *
 * Notes:
 * * FIXME: ERROR messages don't do anything.
 *
 * (c)2005 Sean Russell
 */
public abstract class Stomp {
  /**
   * A map of channel => listener pairs.  String => Listener.
   */
  private Map _listeners = new HashMap();
  /**
   * Things that are listening for communication errors.  Contains
   * Listeners.
   */
  private List _error_listeners = new ArrayList();
  /**
   * A message queue; where messages that have no listeners are
   * stored.  Contains Messages.
   */
  private Stack _queue = new Stack();
  /**
   * Incoming receipts (as String IDs)
   */
  private List _receipts = new ArrayList();
  /**
   * True if connected to a server; false otherwise
   */
  protected boolean _connected = false;
  /**
   * Incoming errors (as String messages)
   */
  private List _errors = new ArrayList();

  /**
   * Disconnect from a server, including headers.
   * Must be implemented by the child class.  Should set the
   * _connected flag to false.
   *
   * @param header A map of key/value headers
   */
  public abstract void disconnect( Map header );

  /**
   * Transmit a message to a server.  Must be implemented by the child class.
   * The implementation must handle cases where the header and/or the body
   * are null.
   *
   * @param command The Stomp command.  If null, causes an error.
   * @param header  A map of headers.  If null, an empty map is used.
   * @param body    The body of the message.  May be empty.
   */
  protected abstract void transmit( Command command, Map header, String body );

  /**
   * Disconnect from a server.  Must be implemented by the child class.
   */
  public void disconnect() { disconnect( null ); }

  /**
   * Transmit a message to a server.
   *
   * @param command The Stomp command.  If null, causes an error.
   * @param header  A map of headers.  If null, an empty map is used.
   */
  protected void transmit( Command command, Map header ) {
    transmit( command, header, null );
  }

  /**
   * Transmit a message to a server.
   *
   * @param command The Stomp command.  If null, causes an error.
   */
  protected void transmit( Command command ) {
    transmit( command, null, null );
  }

  /**
   * Begins a transaction.  Messages will not be delivered to
   * subscribers until commit() has been called.
   */
  public void begin() { transmit( Command.BEGIN ); }

  /**
   * Begins a transaction.  Messages will not be delivered to
   * subscribers until commit() has been called.
   *
   * @param header Additional headers to send to the server.
   */
  public void begin( Map header ) { transmit( Command.BEGIN, header ); }

  /**
   * Commits a transaction, causing any messages sent since begin()
   * was called to be delivered.
   */
  public void commit() { transmit( Command.COMMIT ); }

  /**
   * Commits a transaction, causing any messages sent since begin()
   * was called to be delivered.
   *
   * @param header Additional headers to send to the server.
   */
  public void commit( Map header ) { transmit( Command.BEGIN, header ); }

  /**
   * Commits a transaction, causing any messages sent since begin()
   * was called to be delivered.  This method does not return until
   * the server has confirmed that the commit was successfull.
   */
  public void commitW() throws InterruptedException { commitW( null ); }

  /**
   * Commits a transaction, causing any messages sent since begin()
   * was called to be delivered.  This method does not return until
   * the server has confirmed that the commit was successfull.
   */
  public void commitW( Map header ) throws InterruptedException {
    String receipt = addReceipt( header );
    transmit( Command.COMMIT, header );
    waitOnReceipt( receipt );
  }

  /**
   * Aborts a transaction.  Messages sent since begin() was called
   * are destroyed and are not sent to subscribers.
   */
  public void abort() { transmit( Command.ABORT ); }

  /**
   * Aborts a transaction.  Messages sent since begin() was called
   * are destroyed and are not sent to subscribers.
   *
   * @param header Additional headers to send to the server.
   */
  public void abort( Map header ) { transmit( Command.ABORT, header ); }

  /**
   * Subscribe to a channel.
   *
   * @param name The name of the channel to listen on
   */
  public void subscribe( String name ) {
    subscribe( name, null, null );
  }

  /**
   * Subscribe to a channel.
   *
   * @param name The name of the channel to listen on
   * @param header Additional headers to send to the server.
   */
  public void subscribe( String name, Map header ) {
    subscribe( name, null, header );
  }

  /**
   * Subscribe to a channel.
   *
   * @param name The name of the channel to listen on
   * @param listener A listener to receive messages sent to the channel
   */
  public void subscribe( String name, Listener listener ) {
    subscribe( name, listener, null );
  }

  /**
   * Subscribe to a channel.
   *
   * @param name The name of the channel to listen on
   * @param headers Additional headers to send to the server.
   * @param listener A listener to receive messages sent to the channel
   */
  public void subscribe( String name,  Listener listener, Map headers ) {
    synchronized (_listeners) {
      if (listener != null) {
        List list = (List)_listeners.get( name );
        if (list == null) {
          list = new ArrayList();
          _listeners.put( name, list );
        }
        if (!list.contains( listener )) list.add( listener );
      }
    }
    if (headers == null) headers = new HashMap();
    headers.put( "destination", name );
    transmit( Command.SUBSCRIBE, headers );
  }

  private String addReceipt( Map header ) {
    if (header == null) header = new HashMap();
    String receipt = String.valueOf(hashCode())+"&"+System.currentTimeMillis();
    header.put( "receipt",receipt );
    return receipt;
  }

  /**
   * Subscribe to a channel.  This method blocks until it receives a
   * receipt from the server.
   *
   * @param name The name of the channel to listen on
   * @param header Additional headers to send to the server.
   * @param listener A listener to receive messages sent to the channel
   */
  public void subscribeW( String name, Listener listener, Map header )
  throws InterruptedException {
    String receipt = addReceipt( header );
    subscribe( name, listener, header );
    waitOnReceipt( receipt );
  }

  /**
   * Subscribe to a channel.  This method blocks until it receives a
   * receipt from the server.
   *
   * @param name The name of the channel to listen on
   * @param listener A listener to receive messages sent to the channel
   */
  public void subscribeW( String name, Listener listener )
  throws InterruptedException {
    subscribeW( name, listener, null );
  }

  /**
   * Unsubscribe from a channel.  Automatically unregisters all
   * listeners of the channel.  To re-subscribe with listeners,
   * subscribe must be passed the listeners again.
   *
   * @param name The name of the channel to unsubscribe from.
   */
  public void unsubscribe( String name ) {
    unsubscribe( name, (HashMap)null );
  }

  /**
   * Unsubscribe a single listener from a channel.  This does not
   * send a message to the server unless the listener is the only
   * listener of this channel.
   *
   * @param name The name of the channel to unsubscribe from.
   * @param l The listener to unsubscribe
   */
  public void unsubscribe( String name, Listener l ) {
    synchronized (_listeners) {
      List list = (List)_listeners.get( name );
      if (list != null) {
        list.remove( l );
        if (list.size() == 0) {
          unsubscribe( name );
        }
      }
    }
  }
  /**
   * Unsubscribe from a channel.  Automatically unregisters all
   * listeners of the channel.  To re-subscribe with listeners,
   * subscribe must be passed the listeners again.
   *
   * @param name The name of the channel to unsubscribe from.
   * @param header Additional headers to send to the server.
   */
  public void unsubscribe( String name, Map header ) {
    if (header == null) header = new HashMap();
    synchronized( _listeners ) { _listeners.remove( name ); }
    header.put( "destination", name );
    transmit( Command.UNSUBSCRIBE, header );
  }

  /**
   * Unsubscribe from a channel.  Automatically unregisters all
   * listeners of the channel.  To re-subscribe with listeners,
   * subscribe must be passed the listeners again.  This method
   * blocks until a receipt is received from the server.
   *
   * @param name The name of the channel to unsubscribe from.
   */
  public void unsubscribeW( String name ) throws InterruptedException {
    unsubscribe( name, (HashMap)null );
  }

  /**
   * Unsubscribe from a channel.  Automatically unregisters all
   * listeners of the channel.  To re-subscribe with listeners,
   * subscribe must be passed the listeners again.  This method
   * blocks until a receipt is received from the server.
   *
   * @param name The name of the channel to unsubscribe from.
   */
  public void unsubscribeW( String name, Map header ) throws InterruptedException {
    String receipt = addReceipt( header );
    unsubscribe( name, (HashMap)null );
    waitOnReceipt( receipt );
  }

  /**
   * Send a message to a channel synchronously.  This method does
   * not return until the server acknowledges with a receipt.
   *
   * @param dest The name of the channel to send the message to
   * @param mesg The message to send.
   */
  public void sendW( String dest, String mesg )
    throws InterruptedException {
    sendW( dest, mesg, null );
  }

  /**
   * Send a message to a channel synchronously.  This method does
   * not return until the server acknowledges with a receipt.
   *
   * @param dest The name of the channel to send the message to
   * @param mesg The message to send.
   */
  public void sendW( String dest, String mesg, Map header )
    throws InterruptedException {
    String receipt = addReceipt( header );
    send( dest, mesg, header );
    waitOnReceipt( receipt );
  }

  /**
   * Send a message to a channel.
   *
   * @param dest The name of the channel to send the message to
   * @param mesg The message to send.
   */
  public void send( String dest, String mesg ) {
    send( dest, mesg, null );
  }

  /**
   * Send a message to a channel.
   *
   * @param dest The name of the channel to send the message to
   * @param mesg The message to send.
   * @param header Additional headers to send to the server.
   */
  public void send( String dest, String mesg, Map header ) {
    if (header == null) header = new HashMap();
    header.put( "destination", dest );
    transmit( Command.SEND, header, mesg );
  }

  /**
   * Get the next unconsumed message in the queue.  This is non-blocking.
   *
   * @return the next message in the queue, or null if the queue
   *  contains no messages.  This is non-blocking.
   */
  public Message getNext() {
    synchronized(_queue) { return (Message)_queue.pop(); }
  }

  /**
   * Get the next unconsumed message for a particular channel.   This is
   * non-blocking.
   *
   * @param name the name of the channel to search for
   *
   * @return the next message for the channel, or null if the queue
   *  contains no messages for the channel.
   */
  public Message getNext( String name ) {
    synchronized( _queue ) {
      for (int idx = 0; idx < _queue.size(); idx++) {
        Message m = (Message)_queue.get(idx);
        if (m.headers().get( "destination" ).equals(name)) {
          _queue.remove(idx);
          return m;
        }
      }
    }
    return null;
  }

  public void addErrorListener( Listener l ) {
    synchronized (_error_listeners) { _error_listeners.add( l ); }
  }

  public void delErrorListener( Listener l ) {
    synchronized (_error_listeners) { _error_listeners.remove( l ); }
  }

  /**
   * Checks to see if a receipt has come in.
   *
   * @param receipt_id the id of the receipts to find
   */
  public boolean hasReceipt( String receipt_id ) {
    synchronized( _receipts ) {
      for (Iterator i=_receipts.iterator(); i.hasNext();) {
        String o = (String)i.next();
        if (o.equals(receipt_id)) return true;
      }
    }
    return false;
  }

  /**
   * Deletes all receipts with a given ID
   *
   * @param receipt_id the id of the receipts to delete
   */
  public void clearReceipt( String receipt_id ) {
    synchronized( _receipts ) {
      for (Iterator i=_receipts.iterator(); i.hasNext();) {
        String o = (String)i.next();
        if (o.equals(receipt_id)) i.remove();
      }
    }
  }

  /**
   * Remove all of the receipts
   */
  public void clearReceipts() {
    synchronized( _receipts ) {
      _receipts.clear();
    }
  }

  public void waitOnReceipt( String receipt_id )
    throws java.lang.InterruptedException {
    synchronized( _receipts ) {
      while (!hasReceipt(receipt_id))
        _receipts.wait();
    }
  }
  public boolean waitOnReceipt( String receipt_id, long timeout )
    throws java.lang.InterruptedException {
    synchronized( _receipts ) {
      while (!hasReceipt(receipt_id ))
        _receipts.wait( timeout );
      if (_receipts.contains( receipt_id )) {
        return true;
      } else {
        return false;
      }
    }
  }

  public boolean isConnected() { return _connected; }

  public String nextError() {
    /*
    StackTraceElement[] trace = new Throwable().getStackTrace();
    StringBuffer buff = new StringBuffer();
    for (int i=0; i<trace.length; buff.append( trace[i].getClassName()+":"+trace[i++].getLineNumber()+" << " ));
    System.err.println("In nextError with "+_errors.size()+" errors from "+buff.toString());
    */
    synchronized( _errors ) {
      if (_errors.size() == 0) return null;
      return (String)_errors.remove(0);
    }
  }

  public void receive( Command c, Map h, String b ) {
    if (c == Command.MESSAGE ) {
      String destination = (String)h.get( "destination" );
      synchronized( _listeners ) {
        List listeners = (List)_listeners.get( destination );
        if (listeners != null) {
          listeners = new ArrayList( listeners );
          for (Iterator i = listeners.iterator(); i.hasNext(); ) {
            Listener l = (Listener)i.next();
            try {
              l.message( h, b );
            } catch (Exception e) {
              // Don't let listeners screw us over by throwing exceptions
            }
          }
        } else {
          _queue.push( new Message( c, h, b ) );
        }
      }

    } else if (c == Command.CONNECTED ) {
      _connected = true;

    } else if (c == Command.RECEIPT ) {
      _receipts.add( h.get("receipt-id") );
      synchronized(_receipts) { _receipts.notify(); }

    } else if (c == Command.ERROR ) {
      if (_error_listeners.size() > 0) {
        synchronized (_error_listeners) {
          for (Iterator i = _error_listeners.iterator(); i.hasNext(); ) {
            try {
              ((Listener)i.next()).message( h, b );
            } catch (Exception e) {
              // Don't let listeners screw us over by throwing exceptions
            }
          }
        }
      } else {
        synchronized( _errors ) {
          _errors.add( b );
        }
      }
    } else {
      // FIXME
    }
  }
}


package hudson.plugins.dry.parser.simian;

import hudson.plugins.analysis.util.PackageDetectors;
import hudson.plugins.dry.parser.AbstractDryParser;
import hudson.plugins.dry.parser.DuplicateCode;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.commons.digester.Digester;
import org.xml.sax.SAXException;

/**
 * A parser for Simian XML files.
 *
 * @author Ulli Hafner
 */
public class SimianParser extends AbstractDryParser {
    /** Unique ID of this class. */
    private static final long serialVersionUID = 6507147028628714706L;

    /**
     * Creates a new instance of {@link SimianParser}.
     *
     * @param highThreshold
     *            minimum number of duplicate lines for high priority warnings
     * @param normalThreshold
     *            minimum number of duplicate lines for normal priority warnings
     */
    public SimianParser(final int highThreshold, final int normalThreshold) {
        super(highThreshold, normalThreshold);
    }

    @Override
    public boolean accepts(final InputStream file) {
        try {
            Digester digester = new Digester();
            digester.setValidating(false);
            digester.setClassLoader(SimianParser.class.getClassLoader());

            String duplicationXPath = "*/simian";
            digester.addObjectCreate(duplicationXPath, String.class);

            Object result = digester.parse(file);
            if (result instanceof String) {
                return true;
            }

        }
        catch (IOException exception) {
            // ignore and return false
        }
        catch (SAXException exception) {
            // ignore and return false
        }
        return false;
    }

    @Override
    public Collection<DuplicateCode> parse(final InputStream file, final String moduleName) throws InvocationTargetException {
        try {
            Digester digester = new Digester();
            digester.setValidating(false);
            digester.setClassLoader(SimianParser.class.getClassLoader());

            ArrayList<Set> duplications = new ArrayList<Set>();
            digester.push(duplications);

            String duplicationXPath = "*/simian/check/set";
            digester.addObjectCreate(duplicationXPath, Set.class);
            digester.addSetProperties(duplicationXPath);
            digester.addSetNext(duplicationXPath, "add");

            String fileXPath = duplicationXPath + "/block";
            digester.addObjectCreate(fileXPath, Block.class);
            digester.addSetProperties(fileXPath);
            digester.addSetNext(fileXPath, "addBlock", Block.class.getName());

            Object result = digester.parse(file);
            if (result != duplications) { // NOPMD
                throw new SAXException("Input stream is not a valid Simian file.");
            }

            return convert(duplications, moduleName);
        }
        catch (IOException exception) {
            throw new InvocationTargetException(exception);
        }
        catch (SAXException exception) {
            throw new InvocationTargetException(exception);
        }
    }

    /**
     * Converts the internal structure to the annotations API.
     *
     * @param duplications
     *            the internal maven module
     * @param moduleName
     *            name of the maven module
     * @return a maven module of the annotations API
     */
    private Collection<DuplicateCode> convert(final List<Set> duplications, final String moduleName) {
        List<DuplicateCode> annotations = new ArrayList<DuplicateCode>();

        for (Set duplication : duplications) {
            List<DuplicateCode> codeBlocks = new ArrayList<DuplicateCode>();
            boolean isDerived = false;
            for (Block file : duplication.getBlocks()) {
                DuplicateCode annotation = new DuplicateCode(getPriority(duplication.getLineCount()), file.getStartLineNumber(), duplication.getLineCount(), file.getSourceFile(), isDerived);
                annotation.setModuleName(moduleName);
                codeBlocks.add(annotation);
                isDerived = true;
            }
            for (DuplicateCode block : codeBlocks) {
                block.linkTo(codeBlocks);

                String packageName = PackageDetectors.detectPackageName(block.getFileName());
                block.setPackageName(packageName);
            }
            annotations.addAll(codeBlocks);
        }
        return annotations;
    }
}


package com.azaptree.services.eventbus.impl;

/*
 * #%L
 * EventBus Service
 * %%
 * Copyright (C) 2012 AZAPTREE.COM
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */

import java.lang.reflect.Method;
import java.util.concurrent.Executor;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.BeanNameAware;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import com.azaptree.services.eventbus.EventBusService;
import com.google.common.eventbus.AsyncEventBus;
import com.google.common.eventbus.DeadEvent;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;

/**
 * By default, the Spring bean name is used as the EventBus name.
 *
 * Registers a DeadEvent event handler. Dead events are events that posted, but there are no registered subscribers for that
 * event type. When a DeadEvent is received, it logs a WARNING message.
 *
 * @author Alfio Zappala
 *
 */
@Service
@ManagedResource
public class EventBusServiceImpl implements EventBusService, BeanNameAware {

	private EventBus eventBus;
	private Executor executor;
	private String beanName;
	private String eventBusName;

	/**
	 * Creates a synchronous EventBus, i.e., events are dispatched on the same thread.
	 *
	 * The beanName is used as the EventBus identifier.
	 */
	public EventBusServiceImpl() {
	}

	/**
	 * Creates an AsyncEventBus
	 *
	 * @param executor
	 */
	public EventBusServiceImpl(final Executor executor) {
		Assert.notNull(executor);
		this.executor = executor;
	}

	public EventBusServiceImpl(final String eventBusName) {
		init(eventBusName, null);
	}

	public EventBusServiceImpl(final String eventBusName, final Executor executor) {
		init(eventBusName, executor);
	}

	private void checkSubscribeMethodExists(final Object eventHandler) {
		for (final Method m : eventHandler.getClass().getMethods()) {
			if (m.getAnnotation(Subscribe.class) != null) {
				return;
			}
		}

		throw new IllegalArgumentException("eventHandler has no methods annotated with @Subscribe");
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see com.azaptree.services.eventbus.impl.EventBusServiceJmxApi#getEventBusName()
	 */
	@Override
	@ManagedAttribute
	public String getEventBusName() {
		return eventBusName;
	}

	@PostConstruct
	public void init() {
		init(beanName, executor);
	}

	public void init(final String eventBusName, final Executor executor) {
		if (eventBus != null) {
			log.debug("eventBus has already been created");
			return;
		}

		Assert.hasText(eventBusName, "eventBusName is required");
		this.eventBusName = eventBusName;

		if (executor != null) {
			eventBus = new AsyncEventBus(eventBusName, executor);
		} else {
			eventBus = new EventBus(eventBusName);
		}

		eventBus.register(this);
		log.info("Created EventBus: {} -> {}", beanName, eventBus.getClass().getName());
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see com.azaptree.services.eventbus.impl.EventBusServiceJmxApi#isAsynchronous()
	 */
	@Override
	@ManagedAttribute
	public boolean isAsynchronous() {
		if (eventBus == null) {
			throw new IllegalStateException("EventBus has not yet been created");
		}
		return eventBus instanceof AsyncEventBus;
	}

	/**
	 * Logs dead event as warnings. Dead events are events that posted, but there are no registered subscribers for that
	 * event type.
	 *
	 * @param deadEvent
	 */
	@Subscribe
	public void logDeadEvent(final DeadEvent deadEvent) {
		final Object event = deadEvent.getEvent();
		log.warn("{} : DeadEvent : {} : {}", beanName, event.getClass().getName(), event);
	}

	@Override
	public void post(final Object event) {
		Assert.notNull(event, "event is required");
		eventBus.post(event);
	}

	@Override
	public void register(final Object eventHandler) {
		Assert.notNull(eventHandler, "eventHandler is required");
		checkSubscribeMethodExists(eventHandler);
		eventBus.register(eventHandler);
		log.info("{} : registered event handler: {} ", beanName, eventHandler.getClass().getName());
	}

	@Override
	public void setBeanName(final String name) {
		Assert.hasText(name);
		beanName = name;
	}

	@Override
	public void unregister(final Object eventHandler) {
		Assert.notNull(eventHandler, "eventHandler is required");
		eventBus.unregister(eventHandler);
		log.info("{} : unregistered event handler: {} ", beanName, eventHandler.getClass().getName());
	}
}


/**
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.deephacks.tools4j.cli;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.deephacks.tools4j.cli.Conversion.Converter.ObjectToStringConverter;
import org.deephacks.tools4j.cli.Conversion.Converter.StringToBooleanConverter;
import org.deephacks.tools4j.cli.Conversion.Converter.StringToEnumConverter;
import org.deephacks.tools4j.cli.Conversion.Converter.StringToNumberConverter;
import org.deephacks.tools4j.cli.Conversion.Converter.StringToObjectConverter;

/**
 * Conversion is responsible for converting values using registered converters.
 *
 * Inspiration from http://www.springsource.org
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
final class Conversion {
    /** Keeper for converters available. */
    private final HashMap<Class<?>, SourceTargetPair> converters = new HashMap<Class<?>, SourceTargetPair>();
    /** Lookup cache for finding converters. */
    private final ConcurrentHashMap<SourceTargetPairKey, Converter> cache = new ConcurrentHashMap<SourceTargetPairKey, Converter>();

    private static Conversion INSTANCE;

    private Conversion() {
        registerDefault();
    }

    public static synchronized Conversion get() {
        if (INSTANCE == null) {
            INSTANCE = new Conversion();

        }
        return INSTANCE;
    }

    /**
     * Convert a value to a specific class.
     *
     * The algorithm for finding a suitable converter is as follows:
     *
     * Find converters that is able to convert both source and target; a exact or
     * superclass match. Pick the converter that have the best target match, if both
     * are equal, pick the one with best source match.
     *
     * That is, the converter that is most specialized in converting a value to
     * a specific target class will be prioritized, as long as it recognizes the source
     * value.
     *
     * @param source value to convert.
     * @param targetclass class to convert to.
     * @return converted value
     */
    public <T> T convert(final Object source, final Class<T> targetclass) {
        if (source == null) {
            return null;
        }

        final Class<?> sourceclass = source.getClass();
        final SourceTargetPairKey key = new SourceTargetPairKey(sourceclass, targetclass);
        Converter converter = cache.get(key);

        if (converter != null) {
            return (T) converter.convert(source, targetclass);
        }
        final LinkedList<SourceTargetPairMatch> matches = new LinkedList<SourceTargetPairMatch>();
        for (SourceTargetPair pair : converters.values()) {
            SourceTargetPairMatch match = pair.match(sourceclass, targetclass);
            if (match.matchesSource() && match.matchesTarget()) {
                matches.add(match);
            }
        }
        if (matches.size() == 0) {
            throw new ConversionException("No suitable converter found for target class ["
                    + targetclass.getName() + "] and source value [" + sourceclass.getName()
                    + "]. The following converters are available [" + converters.keySet() + "]");
        }

        Collections.sort(matches, SourceTargetPairMatch.bestTargetMatch());
        converter = matches.get(0).pair.converter;
        cache.put(key, converter);
        return (T) converter.convert(source, targetclass);

    }

    public <T, V> Collection<T> convert(Collection<V> values, final Class<T> clazz) {
        final ArrayList<T> objects = new ArrayList<T>();
        if (values == null) {
            return new ArrayList<T>();
        }
        for (V object : values) {
            objects.add(convert(object, clazz));
        }
        return objects;
    }

    public <T, V> Map<V, T> convert(Map<V, Object> values, final Class<T> clazz) {
        if (values == null) {
            return null;
        }
        throw new UnsupportedOperationException();
    }

    public <T, V> void register(Converter converter) {
        if (converters.get(converter.getClass()) != null) {
            return;
        }
        converters.put(converter.getClass(), new SourceTargetPair(converter));
        cache.clear();

    }

    private void registerDefault() {
        register(new StringToEnumConverter());
        register(new StringToObjectConverter());
        register(new ObjectToStringConverter());
        register(new StringToNumberConverter());
        register(new StringToBooleanConverter());
    }

    private static class SourceTargetPair {
        private final Class<?> source;
        private final Class<?> target;
        private final Converter converter;

        public SourceTargetPair(Converter converter) {
            List<Class<?>> types = getParameterizedType(converter.getClass(), Converter.class);
            if (types.size() < 2) {
                throw new IllegalArgumentException(
                        "Unable to the determine generic source and target type "
                                + "for converter. Please declare these generic types.");
            }
            this.source = types.get(0);
            this.target = types.get(1);
            this.converter = converter;
        }

        public SourceTargetPairMatch match(Class<?> sourceValueClass, Class<?> targetClass) {
            return new SourceTargetPairMatch(this, getSourceMatchDistance(sourceValueClass),
                    getTargetMatchDistance(targetClass));
        }

        /**
         * Returns a list of classes that matches the candidate in terms
         * of converter source. The list is sorted with the most specific match first.
         */
        private int getSourceMatchDistance(Class<?> candidate) {
            return distance(candidate, source);
        }

        /**
         * Returns a list of classes that matches the candidate in terms
         * of converter target. The list is sorted with the most specific match first.
         */
        private int getTargetMatchDistance(Class<?> candidate) {
            return distance(candidate, target);
        }

        /**
         * Climb the class hierarchy of the candidate class and calculate the distance
         * between to the capability class.
         *
         * @return The distance in the class hierarchy between the candidate and capability.
         */
        private int distance(Class<?> candidate, Class<?> capability) {
            int distance = 0;
            if (candidate == capability) {
                return distance;
            }
            final LinkedList<Class<?>> superclasses = new LinkedList<Class<?>>();
            superclasses.add(candidate.getSuperclass());
            while (!superclasses.isEmpty()) {
                Class<?> candidateSuperclazz = superclasses.removeLast();
                if (candidateSuperclazz == null) {
                    // Object converters are absolute last resort
                    return Integer.MAX_VALUE;
                }
                if (candidateSuperclazz.equals(capability)) {
                    if (capability == Object.class) {
                        // Object converters are absolute last resort
                        return Integer.MAX_VALUE;
                    }
                    return ++distance;
                }
                addInterfaces(candidateSuperclazz, superclasses);
                if (candidateSuperclazz.getSuperclass() != null) {
                    superclasses.add(candidateSuperclazz.getSuperclass());
                }
            }
            // no match
            return -1;
        }

        private void addInterfaces(Class<?> clazz, LinkedList<Class<?>> superclasses) {
            for (Class<?> inheritedIfc : clazz.getInterfaces()) {
                addInterfaces(inheritedIfc, superclasses);
            }
        }
    }

    private static class SourceTargetPairMatch {
        private int bestTargetMatch = -1;
        private int bestSourceMatch = -1;
        private final SourceTargetPair pair;

        public SourceTargetPairMatch(SourceTargetPair pair, int bestSourceMatch, int bestTargetMatch) {
            this.pair = pair;
            this.bestSourceMatch = bestSourceMatch;
            this.bestTargetMatch = bestTargetMatch;
        }

        public boolean matchesTarget() {
            return (bestTargetMatch > -1 ? true : false);
        }

        public boolean matchesSource() {
            return (bestSourceMatch > -1 ? true : false);
        }

        public static Comparator<SourceTargetPairMatch> bestTargetMatch() {
            return new Comparator<Conversion.SourceTargetPairMatch>() {

                @Override
                public int compare(SourceTargetPairMatch o1, SourceTargetPairMatch o2) {
                    if (o1.bestTargetMatch < o2.bestTargetMatch) {
                        return -1;
                    } else if (o1.bestTargetMatch > o2.bestTargetMatch) {
                        return 1;
                    }
                    // equal target, pick best source.
                    if (o1.bestSourceMatch < o2.bestSourceMatch) {
                        return -1;
                    } else if (o1.bestSourceMatch > o2.bestSourceMatch) {
                        return 1;
                    }
                    return 0;
                }
            };
        }
    }

    private static class SourceTargetPairKey {
        final Class<?> source;
        final Class<?> target;

        public SourceTargetPairKey(Class<?> source, Class<?> target) {
            this.source = source;
            this.target = target;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((source == null) ? 0 : source.hashCode());
            result = prime * result + ((target == null) ? 0 : target.hashCode());
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            SourceTargetPairKey other = (SourceTargetPairKey) obj;
            if (source == null) {
                if (other.source != null)
                    return false;
            } else if (!source.equals(other.source))
                return false;
            if (target == null) {
                if (other.target != null)
                    return false;
            } else if (!target.equals(other.target))
                return false;
            return true;
        }

    }

    /**
     * Returns the parameterized type of a class, if exists. Wild cards, type
     * variables and raw types will be returned as an empty list.
     *

     * If a field is of type Set<String> then java.lang.String is returned.
     *

     *

     * If a field is of type Map<String, Integer> then [java.lang.String,
     * java.lang.Integer] is returned.
     *

     *
     * @param ownerClass the implementing target class to check against
     * @param the generic interface to resolve the type argument from
     * @return A list of classes of the parameterized type.
     */
    public static List<Class<?>> getParameterizedType(final Class<?> ownerClass,
            Class<?> genericSuperClass) {
        Type[] types = null;
        if (genericSuperClass.isInterface()) {
            types = ownerClass.getGenericInterfaces();
        } else {
            types = new Type[] { ownerClass.getGenericSuperclass() };
        }

        final List<Class<?>> classes = new ArrayList<Class<?>>();
        for (Type type : types) {

            if (!ParameterizedType.class.isAssignableFrom(type.getClass())) {
                // the field is it a raw type and does not have generic type
                // argument. Return empty list.
                return new ArrayList<Class<?>>();
            }

            final ParameterizedType ptype = (ParameterizedType) type;
            final Type[] targs = ptype.getActualTypeArguments();

            for (Type aType : targs) {

                classes.add(extractClass(ownerClass, aType));
            }
        }
        return classes;
    }

    private static Class<?> extractClass(Class<?> ownerClass, Type arg) {
        if (arg instanceof ParameterizedType) {
            return extractClass(ownerClass, ((ParameterizedType) arg).getRawType());
        } else if (arg instanceof GenericArrayType) {
            throw new UnsupportedOperationException("GenericArray types are not supported.");
        } else if (arg instanceof TypeVariable) {
            throw new UnsupportedOperationException("GenericArray types are not supported.");
        }
        return (arg instanceof Class ? (Class<?>) arg : Object.class);
    }

    static class ConversionException extends RuntimeException {
        private static final long serialVersionUID = 3116958531528669531L;

        public ConversionException(String msg) {
            super(msg);
        }

        public ConversionException(Throwable e) {
            super(e);
        }

        public ConversionException(String msg, Exception e) {
            super(msg, e);
        }
    }

    /**
     * Converts a object of type V to a object of type T.
     *
     * Both V and T can be a super class or interface that handles a range of
     * subclasses.
     *
     * The algorithm for finding a suitable converter begins by first finding
     * converters that are able to convert both source and target; a exact or
     * superclass match. The final decision falls on the converter that have
     * the best target match.
     *
     * That is, the converter that is most specialized in converting a value T to
     * a specific target class will be prioritized, as long as it recognizes
     * the source value V.
     *
     * Converter providers are regsitered using the standard java service provider
     * mechanism.
     */
    interface Converter<V, T> {
        /**
         * @param source The source value to convert.
         * @param the most specific type that the value should be converted to.
         * @return A converted object.
         */
        public T convert(V source, Class<? extends T> specificType);

        /**
         * This is the fallback string converter that simply does a toString on the
         * provided object.
         *
         * Works fine for Number, Boolean, Enums and all other values that have a
         * toString that represent their real values in a serialized form.
         */
        static final class ObjectToStringConverter implements Converter<Object, String> {

            @Override
            public String convert(Object source, Class<? extends String> specificType) {
                return (source != null ? source.toString() : null);
            }

        }

        static final class StringToBooleanConverter implements Converter<String, Boolean> {
            private static final Set<String> trueValues = new HashSet<String>();
            private static final Set<String> falseValues = new HashSet<String>();

            static {
                trueValues.addAll(Arrays.asList("true", "on", "yes", "y", "1"));
                falseValues.addAll(Arrays.asList("false", "off", "no", "n", "0"));
            }

            @Override
            public Boolean convert(String source, Class<? extends Boolean> specificType) {
                final String value = source.trim();
                if (trueValues.contains(value)) {
                    return Boolean.TRUE;
                } else if (falseValues.contains(value)) {
                    return Boolean.FALSE;
                } else {
                    throw new ConversionException("Invalid boolean value '" + source + "'");
                }
            }

        }

        /**
         * This class can convert any enum to a string.
         */
        static final class StringToEnumConverter implements Converter<String, Enum> {

            @Override
            public Enum convert(String source, Class<? extends Enum> specificType) {
                try {
                    return Enum.valueOf(specificType, source);
                } catch (IllegalArgumentException e) {
                    throw new ConversionException("Could not convert value [" + source
                            + "] to any of the possible values:  "
                            + getPossibleValueString(specificType) + ".");
                }
            }

            public String getPossibleValueString(Class<?> clazz) {
                StringBuffer sb = new StringBuffer();
                Field[] fields = clazz.getDeclaredFields();
                List<String> values = new ArrayList<String>();
                for (int i = 0; i < fields.length; i++) {
                    if (fields[i].isEnumConstant()) {
                        try {
                            Object aEnum = fields[i].get(null);
                            values.add(aEnum.toString());
                        } catch (Exception e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
                for (int i = 0; i < values.size(); i++) {
                    sb.append(values.get(i));
                    if ((i + 1) != values.size()) {
                        sb.append(", ");
                    }
                }
                return sb.toString();
            }

        }

        /**
         * This class can convert all number types such as BigDecimal, BigInteger, Byte, Double,
         * Float, Integer, Long, and Short.
         */
        static final class StringToNumberConverter implements Converter<String, Number> {

            @Override
            public Number convert(String source, Class<? extends Number> specificType) {
                final String value = source.trim();
                try {
                    if (specificType.equals(Byte.class)) {
                        return Byte.valueOf(value);
                    } else if (specificType.equals(Short.class)) {
                        return Short.valueOf(value);
                    } else if (specificType.equals(Integer.class)) {
                        return Integer.valueOf(value);
                    } else if (specificType.equals(Long.class)) {
                        return Long.valueOf(value);
                    } else if (specificType.equals(BigInteger.class)) {
                        return new BigInteger(value);
                    } else if (specificType.equals(Float.class)) {
                        return Float.valueOf(value);
                    } else if (specificType.equals(Double.class)) {
                        return Double.valueOf(value);
                    } else if (specificType.equals(BigDecimal.class)
                            || specificType.equals(Number.class)) {
                        return new BigDecimal(value);
                    }
                    throw new ConversionException("Cannot convert [" + source + "] to ["
                            + specificType.getName() + "]");

                } catch (NumberFormatException e) {
                    throw new ConversionException("Cannot convert [" + source + "] to ["
                            + specificType.getName() + "]", e);
                }

            }

        }

        /**
         * General purpose converter that is able to convert a String to an object if the
         * object have a suitable static valueof method or a single argument String constructor.
         *
         * This should work fine for File, URL, DateTime, DurationTime
         */
        static final class StringToObjectConverter implements Converter<String, Object> {

            @Override
            public Object convert(String source, Class<? extends Object> specificType) {
                final Method valueof = getStaticMethod(specificType, "valueof", String.class);

                try {
                    if (valueof != null) {
                        valueof.setAccessible(true);
                        return valueof.invoke(null, source);
                    }
                    final Constructor<?> cons = getConstructor(specificType, String.class);
                    if (cons != null) {
                        cons.setAccessible(true);
                        return cons.newInstance(source);
                    }
                } catch (InvocationTargetException e) {
                    throw new ConversionException(e.getTargetException());
                } catch (Throwable e) {
                    throw new ConversionException(e);
                }
                throw new UnsupportedOperationException(
                        "No static valueOf(String.class) method or Constructor(String.class) exists on "
                                + specificType.getName());
            }

            public static <T> Constructor<T> getConstructor(Class<T> clazz, Class<?>... paramTypes) {
                try {
                    return clazz.getConstructor(paramTypes);
                } catch (NoSuchMethodException ex) {
                    return null;
                }
            }

            public static Method getStaticMethod(Class<?> clazz, String methodName,
                    Class<?>... args) {
                try {
                    final Method method = clazz.getMethod(methodName, args);
                    return Modifier.isStatic(method.getModifiers()) ? method : null;
                } catch (NoSuchMethodException ex) {
                    return null;
                }
            }

        }

    }
}


package hudson.plugins.dry.parser;

import hudson.plugins.analysis.core.AnnotationParser;
import hudson.plugins.analysis.util.model.FileAnnotation;
import hudson.plugins.analysis.util.model.Priority;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.Set;

import org.apache.commons.io.IOUtils;

import com.google.common.collect.Sets;

/**
 * A base class for duplicate code parsers. Use this class as a starting point
 * for your duplication result parser and register an instance in the
 * {@link DuplicationParserRegistry}.
 *
 * @author Ulli Hafner
 */
public abstract class AbstractDryParser implements AnnotationParser {
    /** Unique ID of this class. */
    private static final long serialVersionUID = 6328121785037117886L;

    /** Minimum number of duplicate lines for high priority warnings. @since 2.5 */
    private final int highThreshold;
    /** Minimum number of duplicate lines for normal priority warnings. @since 2.5 */
    private final int normalThreshold;

    /**
     * Creates a new instance of {@link AbstractDryParser}.
     *
     * @param highThreshold
     *            minimum number of duplicate lines for high priority warnings
     * @param normalThreshold
     *            minimum number of duplicate lines for normal priority warnings
     */
    public AbstractDryParser(final int highThreshold, final int normalThreshold) {
        this.highThreshold = highThreshold;
        this.normalThreshold = normalThreshold;
    }

    /** {@inheritDoc} */
    public Collection<FileAnnotation> parse(final File file, final String moduleName) throws InvocationTargetException {
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(file);
            if (accepts(inputStream)) {
                IOUtils.closeQuietly(inputStream);
                inputStream = new FileInputStream(file);

                Set<FileAnnotation> warnings = Sets.newHashSet();
                warnings.addAll(parse(inputStream, moduleName));
                return warnings;
            }
            else {
                throw new IOException("Can't parse CPD file " + file.getAbsolutePath());
            }
        }
        catch (IOException exception) {
            throw new InvocationTargetException(exception);
        }
        finally {
            IOUtils.closeQuietly(inputStream);
        }
    }

    /**
     * Returns the duplication annotations found in the specified file.
     *
     * @param inputStream
     *            the file to parse
     * @param moduleName
     *            name of the maven module
     * @return the parsed annotations
     * @throws InvocationTargetException
     *             if the file could not be parsed (wrap your actual exception in this exception)
     */
    protected abstract Collection<DuplicateCode> parse(InputStream inputStream, String moduleName)  throws InvocationTargetException;

    /**
     * Returns whether this parser accepts the specified stream as a valid
     * file.
     *
     * @param inputStream
     *            the file to parse
     * @return true if this parser accepts the specified stream as
     *         a valid file, false if the parser can't read this file
     */
    protected abstract boolean accepts(InputStream inputStream);

    /**
     * Returns the priority of the warning.
     *
     * @param lines
     *            number of duplicate lines
     * @return the priority of the warning
     */
    protected Priority getPriority(final int lines) {
        if (lines >= highThreshold) {
            return Priority.HIGH;
        }
        else if (lines >= normalThreshold) {
            return Priority.NORMAL;
        }
        else {
            return Priority.LOW;
        }
    }
}


package com.thetransactioncompany.cors;

import java.net.URI;
import java.net.URISyntaxException;
import java.net.IDN;

/**
 * Validated resource request origin, as defined in The Web Origin Concept
 * (RFC 6454). Supported schemes are {@code http} and {@code https}.
 *
 * @author Vladimir Dzhuvinov
 * @author Luis Sala
 * @author Jared Ottley
 * @version $version$ (2012-10-19)
 */
public class ValidatedOrigin extends Origin {

	/**
	 * The origin scheme.
	 */
	private String scheme;

	/**
	 * The origin host.
	 */
	private String host;

	/**
	 * The parsed origin port, -1 for default port.
	 */
	private int port = -1;

	/**
	 * Creates a new validated origin from the specified URI string.
	 *
	 * @param value The URI string for the origin. The origin scheme must be
	 *              {@code http} or {@code https}. Must not be {@code null}.
	 *
	 * @throws OriginException If the value doesn't represent a valid and
	 *                         supported origin string.
	 */
	public ValidatedOrigin(final String value)
		throws OriginException {

		super(value);

		// Parse URI value

		URI uri = null;

		try {
			uri = new URI(value);

		} catch (URISyntaxException e) {

			throw new OriginException("Bad origin URI: " + e.getMessage());
		}

		scheme = uri.getScheme();
		host = uri.getHost();
		port = uri.getPort();

		if (scheme == null)
			throw new OriginException("Bad origin URI: Missing scheme, must be http or https");

		// Canonicalise scheme and host

		scheme = scheme.toLowerCase();

		if (! scheme.equals("http") && ! scheme.equals("https"))
			throw new OriginException("Bad origin URI: Scheme must be http or https");

		// Apply the IDNA toASCII algorithm [RFC3490] to /host/
		host = IDN.toASCII(host, IDN.ALLOW_UNASSIGNED | IDN.USE_STD3_ASCII_RULES);

		// Finally, convert to lower case
		host = host.toLowerCase();
	}

	/**
	 * Returns the scheme.
	 *
	 * @return The scheme.
	 */
	public String getScheme() {

		return scheme;
	}

	/**
	 * Returns the host (name or IP address).
	 *
	 * @return The host name or IP address.
	 */
	public String getHost() {

		return host;
	}

	/**
	 * Returns the port number.
	 *
	 * @return The port number, -1 for default port.
	 */
	public int getPort() {

		return port;
	}

	/**
	 * Returns the suffix which is made up of the host name / IP address and
	 * port (if a non-default port is specified).
	 *
	 *
Example:
	 *
	 *

	 * http://example.com => example.com
	 * http://example.com:8080 => example.com:8080
	 *

	 *
	 * @return The suffix.
	 */
	public String getSuffix() {

		String s = host;

		if (port != -1)
			s = s + ":" + port;

		return s;
	}
}


/**
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.deephacks.tools4j.cli;

import org.deephacks.tools4j.cli.Conversion.ConversionException;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.PropertyException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static org.deephacks.tools4j.cli.Utils.validateArgs;
import static org.deephacks.tools4j.cli.Utils.validateOpts;

/**
 * Internal representation of commands.
 */
@XmlAccessorType(XmlAccessType.FIELD)
final class Command {
  /**
   * handle conversion of command input strings to objects
   */
  private static final Conversion c = Conversion.get();
  /**
   * command alias
   */
  @XmlAttribute(name = "cmd")
  private String cmd;
  /**
   * maintain the mapping between command alias and class
   */
  @XmlAttribute(name = "class")
  private String className;
  /**
   * documentation of this command
   */
  @XmlElement(name = "doc")
  private String doc;
  /**
   * options of this command
   */
  @XmlElement(name = "opt")
  private List<Option> options = new ArrayList<Option>();
  /**
   * arguments of this command
   */
  @XmlElement(name = "arg")
  private List<Argument> arguments = new ArrayList<Argument>();
  /**
   * the object instance that will execute the command
   */
  private Object instance;

  public Command() {

  }

  public static List<Command> create(Object command) {
    final List<Command> commands = new ArrayList<Command>();
    final Class<?> cmdClazz = command.getClass();
    for (Method m : cmdClazz.getDeclaredMethods()) {
      m.setAccessible(true);
      final CliCmd anno = m.getAnnotation(CliCmd.class);
      if (anno == null) {
        continue;
      }
      final String cmdname = m.getName();
      final Command cmd = new Command(cmdname, cmdClazz.getName(), "n/a");
      int i = 0;
      for (Class<?> cls : m.getParameterTypes()) {
        cmd.addArgument(new Argument("n/a", cls.getName(), i++, "n/a"));
      }
      commands.add(cmd);
    }
    return commands;
  }

  public Command(String cmd, String className, String doc) {
    this.cmd = cmd;
    this.className = className;
    if (doc == null) {
      this.doc = "";
    } else {
      this.doc = doc;
    }
  }

  /**
   * @return the alias that activates the command.
   */
  public String getCommand() {
    return cmd;
  }

  /**
   * @return raw the documentation of the command, as read from commands.xml.
   */
  public String getDoc() {
    return doc;
  }

  /**
   * Will be treated in the same order as they are added.
   *
   * @param arg argument of this command.
   */
  public void addArgument(Argument arg) {
    arguments.add(arg);
  }

  /**
   * @return all arguments of this command.
   */
  public List<Argument> getArguments() {
    return arguments;
  }

  /**
   * @param opt add an option to this command.
   */
  public void addOptions(Option opt) {
    options.add(opt);
  }

  /**
   * @return all options of this command.
   */
  public List<Option> getOptions() {
    return options;
  }

  /**
   * @param o instance that will handle this command.
   */
  void setInstance(Object o) {
    this.instance = o;
  }

  /**
   * Execute this command according to the user input arguments
   * parsed by the parser.
   */
  public void execute(GNUishParser p) {
    if (instance == null) {
      instance = Utils.newInstance(className);
    }
    final Class<?> clazz = instance.getClass();
    final Method[] methods = clazz.getDeclaredMethods();
    for (Method m : methods) {
      m.setAccessible(true);
      if (!m.getName().equals(p.getCommand())) {
        continue;
      }
      final List<Object> args = adjustArgs(p.getArgs(), m);
      injectOpts(p, clazz);
      try {
        validateArgs(args, instance, m, this);
        m.invoke(instance, args.toArray());
        return;
      } catch (InvocationTargetException e) {
        final Throwable ex = e.getTargetException();
        if (ex instanceof RuntimeException) {
          throw (RuntimeException) e.getCause();
        } else {
          throw new RuntimeException(e.getTargetException());
        }
      } catch (RuntimeException e) {
        throw e;
      } catch (Exception e) {
        throw new RuntimeException(e);
      }
    }
    System.out.println(p.getCommand() + ": command not found");

  }

  /**
   * Convert options to appropriate type and inject them into
   * the command instance.
   */
  private void injectOpts(GNUishParser p, Class<?> clazz) {
    for (Field f : clazz.getDeclaredFields()) {
      f.setAccessible(true);
      final CliOption anno = f.getAnnotation(CliOption.class);
      if (anno == null) {
        continue;
      }
      String value = p.getShortOpt(anno.shortName());
      if (value == null) {
        value = p.getLongOpt(f.getName());
        if (value == null) {
          continue;
        }
      }
      try {
        f.set(instance, c.convert(value, f.getType()));
      } catch (ConversionException e) {
        throw CliException.WRONG_OPT_TYPE(f.getName(), f.getType().getName(), value);
      } catch (Exception e) {
        throw new RuntimeException(e);
      }
    }
    validateOpts(instance);
  }

  /**
   * Add or remove parameters to fit the method declaration and also convert them
   * to appropriate data type.
   */
  private List<Object> adjustArgs(List<String> args, Method m) {
    final List<Object> result = new ArrayList<Object>();
    final Class<?>[] types = m.getParameterTypes();
    if (m.isVarArgs()) {
      types[types.length - 1] = types[types.length - 1].getComponentType();
      if (!String.class.isAssignableFrom(types[types.length - 1])) {
        throw new CliException("Only String varargs is supported.");
      }
      types[types.length - 1] = String.class;
    }

    List<Object> varargs = new ArrayList<>();
    for (int i = 0; i < args.size(); i++) {
      try {
        if (m.isVarArgs() && i >= types.length - 1) {
          varargs.add(c.convert(args.get(i), types[types.length - 1]));
        } else {
          result.add(c.convert(args.get(i), types[i]));
        }
      } catch (ConversionException e) {
        throw CliException.WRONG_ARG_TYPE(getArguments().get(i).getName(),
                types[i].getName(), args.get(i));
      }
    }
    if (m.isVarArgs()) {
      result.add(varargs.toArray(new String[0]));
    }
    return result;
  }

  public String toString() {
    return cmd + " " + className + " " + doc + " " + options + " " + arguments;
  }

  /**
   * Internal representation of options.
   */
  @XmlAccessorType(XmlAccessType.FIELD)
  static final class Option {
    /**
     * short name of this option, triggered using '-'
     */
    @XmlAttribute(name = "short")
    private String shortName;
    /**
     * long name of this option, triggered using '--'
     */
    @XmlAttribute(name = "long")
    private String longName;
    /**
     * documentation of this option
     */
    @XmlElement(name = "doc")
    private String doc;

    public Option() {

    }

    public Option(String shortName, String longName, String doc) {
      this.shortName = shortName;
      this.longName = longName;
      if (doc == null) {
        this.doc = "";
      } else {
        this.doc = doc;
      }

    }

    public String getShortName() {
      return shortName;
    }

    public String getLongName() {
      return longName;
    }

    public String getDoc() {
      return doc;
    }

    public String toString() {
      return shortName + " " + longName + " " + doc;
    }

  }

  /**
   * Internal representation of arguments.
   */
  @XmlAccessorType(XmlAccessType.FIELD)
  static final class Argument {
    @XmlAttribute
    private String name;
    @XmlAttribute
    private int position;
    @XmlAttribute
    private String type;
    @XmlElement(name = "doc")
    private String doc;

    public Argument() {

    }

    public Argument(String name, String type, int position, String doc) {
      this.name = name;
      this.position = position;
      this.type = type;
      if (doc == null) {
        this.doc = "";
      } else {
        this.doc = doc;
      }

    }

    public Class<?> getType() {
      try {
        return Class.forName(type);
      } catch (ClassNotFoundException e) {
        throw new RuntimeException(e);
      }
    }

    public String getName() {
      return name;
    }

    public String getDoc() {
      return doc;
    }

    public String toString() {
      return name + " " + position + " " + doc;
    }

  }

  /**
   * XmlCommands is responsible for converting commands to xml and back.
   */
  @XmlRootElement(name = "command-xml")
  @XmlAccessorType(XmlAccessType.FIELD)
  static final class XmlCommands {
    /**
     * classpath location of command xml file
     */
    public static final String FILEPATH = "META-INF/cli/commands.xml";
    /**
     * available commands
     */
    @XmlElement(name = "command")
    public List<Command> commands = new ArrayList<Command>();

    public XmlCommands() {

    }

    public XmlCommands(Map<String, Command> cmds) {
      for (Command cmd : cmds.values()) {
        this.commands.add(cmd);
      }
    }

    public List<Command> getCommands() {
      return commands;
    }

    /**
     * Convert a set of commands to xml.
     *
     * @param cmds commands to convert
     * @param pw   output to write to
     */
    public static void toXml(Map<String, Command> cmds, PrintWriter pw) {
      try {
        final XmlCommands xml = new XmlCommands(cmds);
        final JAXBContext context = JAXBContext.newInstance(XmlCommands.class);
        final Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(xml, pw);
      } catch (PropertyException e) {
        throw new RuntimeException(e);
      } catch (JAXBException e) {
        throw new RuntimeException(e);
      } finally {
        if (pw != null) {
          pw.flush();
          pw.close();
        }
      }

    }

    /**
     * Create a set of commands from commands.xml.
     *
     * @param in input stream of commands.xml.
     * @return A set of commands.
     */
    public static List<Command> fromXml(InputStream in) {
      try {
        final JAXBContext context = JAXBContext.newInstance(XmlCommands.class);
        final Unmarshaller unmarshaller = context.createUnmarshaller();
        final XmlCommands beans = (XmlCommands) unmarshaller.unmarshal(in);
        return beans.getCommands();
      } catch (JAXBException e) {
        throw new RuntimeException(e);
      } finally {
        if (in != null) {
          try {
            in.close();
          } catch (IOException e) {

          }
        }
      }
    }
  }

}


/**
 * Copyright (C) 2012 Ness Computing, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.nesscomputing.migratory;

import java.util.Collection;
import java.util.List;
import java.util.Map;

import com.google.common.collect.Maps;
import com.nesscomputing.migratory.MigratoryException.Reason;
import com.nesscomputing.migratory.metadata.MetadataInfo;
import com.nesscomputing.migratory.metadata.MetadataManager;
import com.nesscomputing.migratory.migration.DbMigrator;
import com.nesscomputing.migratory.migration.MigrationManager;
import com.nesscomputing.migratory.migration.MigrationPlan;
import com.nesscomputing.migratory.migration.MigrationPlan.MigrationPlanEntry;
import com.nesscomputing.migratory.migration.MigrationPlanner;
import com.nesscomputing.migratory.migration.MigrationResult;
import com.nesscomputing.migratory.migration.MigrationResult.MigrationState;
import com.nesscomputing.migratory.validation.DbValidator;
import com.nesscomputing.migratory.validation.ValidationResult;
import com.nesscomputing.migratory.validation.ValidationResult.ValidationStatus;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

class InternalMigrator extends AbstractMigratorySupport
{
    private static final Logger LOG = LoggerFactory.getLogger(InternalMigrator.class);

    private final MigratoryContext migratoryContext;
    private final MigratoryConfig migratoryConfig;

    InternalMigrator(final MigratoryContext migratoryContext)
    {
        this.migratoryContext = migratoryContext;
        this.migratoryConfig = migratoryContext.getConfig();
    }

    Map<String, List<MetadataInfo>> migrate(final MigrationPlan migrationPlan, final MigratoryOption [] options) throws MigratoryException
    {
        if (migratoryConfig.isReadOnly()) {
            throw new MigratoryException(Reason.IS_READONLY);
        }

        final MetadataManager metadataManager = new MetadataManager(migratoryContext);

        try {
            metadataManager.ensureMetadata(options);

            final Map<String, List<MetadataInfo>> migrationResults = Maps.newTreeMap();
            final Collection<String> existingPersonalities = metadataManager.retrieveExistingPersonalities();

            MigrationPlan planToExecute = migrationPlan;

            // If no personalities were give, migrate all existing personalities to the latest and greatest version.
            if (planToExecute == null || planToExecute.isEmpty()) {
                planToExecute = new MigrationPlan();
                for (String existingPersonality : existingPersonalities) {
                    migrationPlan.addMigration(existingPersonality);
                }
            }

            // Make sure that all requested personalities either already exist in the
            // database or that they can be created.
            for (final MigrationPlanEntry migrationPlanEntry : planToExecute.getEntries()) {
                final String personalityName = migrationPlanEntry.getPersonalityName();

                try {
                    metadataManager.lock(personalityName);
                    final List<MigrationResult> results = migratePersonality(metadataManager, personalityName, migrationPlanEntry.getTargetVersion(), options);

                    final List<MetadataInfo> personalityMigrationResult = metadataManager.commit(results);
                    if (!personalityMigrationResult.isEmpty()) {
                        migrationResults.put(personalityName, personalityMigrationResult);
                    }

                    final MigrationState state = MigrationResult.determineMigrationState(results);
                    if (state != MigrationState.OK) {
                        break;
                    }
                }
                catch (MigratoryException me) {
                    metadataManager.rollback();
                    throw me;
                }
                catch (RuntimeException re) {
                    metadataManager.rollback();
                    throw re;
                }
            }
            return migrationResults;
        }
        catch (Exception e) {
            throw processException(e);
        }
    }

    /**
     * Performs the migration of a personality. This must be run under the table lock so that only one thread can use it at a time.
     */
    private List<MigrationResult> migratePersonality(final MetadataManager metadataManager, final String personalityName, final Integer targetVersion, final MigratoryOption [] options)
    {
        final Integer currentVersion = metadataManager.getCurrentVersion(personalityName);

        if (currentVersion == null  && !migratoryConfig.isCreatePersonalities()) {
            throw new MigratoryException(Reason.NEW_PERSONALITIES_DENIED);
        }

        // Make sure that the current state of the personality is sane.
        final List<MetadataInfo> history = metadataManager.getPersonalityHistory(personalityName);

        final MigrationManager migrationManager = new MigrationManager(migratoryContext, personalityName);

        // if null, this is a new personality.Don't validate it.
        if (history != null && !history.isEmpty()) {
            // "No verify" option skips this step.
            if (!MigratoryOption.containsOption(MigratoryOption.NO_VERIFY, options)) {
                final DbValidator dbValidator = new DbValidator(migrationManager);
                final ValidationResult validationResult = dbValidator.validate(history);

                if (validationResult.getValidationStatus() != ValidationStatus.OK) {
                    throw new MigratoryException(Reason.VALIDATION_FAILED, "Validation for Personality '%s' failed", personalityName);
                }
            }
            else {
                LOG.info("Skipped verification.");
            }
        }

        final MigrationPlanner migrationPlanner = new MigrationPlanner(migrationManager, currentVersion, targetVersion);

        migrationPlanner.plan();

        LOG.info("{}", migrationPlanner.toString());
        switch(migrationPlanner.getDirection()) {
        case FORWARD:
            if (!migratoryConfig.isAllowRollForward()) {
                throw new MigratoryException(Reason.ROLL_FORWARD_DENIED);
            }
            break;

        case BACK:
            if (!migratoryConfig.isAllowRollBack()) {
                throw new MigratoryException(Reason.ROLL_BACK_DENIED);
            }
            break;

        case DO_NOTHING:
            return null;

        default:
            LOG.warn("Encountered State {}. This should never happen!", migrationPlanner.getDirection());
            return null;
        }

        final DbMigrator migrator = new DbMigrator(migratoryContext, migrationPlanner);
        final List<MigrationResult> results = migrator.migrate(options);
        LOG.info("Migration finished in '{}' steps, result is {}",  results.size(), MigrationResult.determineMigrationState(results));
        return results;
    }
}


package hudson.plugins.dry;

import hudson.maven.MavenAggregatedReport;
import hudson.maven.MavenBuild;
import hudson.maven.MavenModule;
import hudson.maven.MavenModuleSet;
import hudson.maven.MavenModuleSetBuild;
import hudson.model.Action;
import hudson.model.AbstractBuild;
import hudson.plugins.analysis.core.HealthDescriptor;
import hudson.plugins.analysis.core.MavenResultAction;
import hudson.plugins.analysis.core.ParserResult;

import java.util.List;
import java.util.Map;

/**
 * A {@link DryResultAction} for native Maven jobs. This action
 * additionally provides result aggregation for sub-modules and for the main
 * project.
 *
 * @author Ulli Hafner
 */
public class DryMavenResultAction extends MavenResultAction<DryResult> {
    /**
     * Creates a new instance of {@link DryMavenResultAction}.
     *
     * @param owner
     *            the associated build of this action
     * @param healthDescriptor
     *            health descriptor to use
     * @param defaultEncoding
     *            the default encoding to be used when reading and parsing files
     * @param result
     *            the result in this build
     */
    public DryMavenResultAction(final AbstractBuild<?, ?> owner, final HealthDescriptor healthDescriptor,
            final String defaultEncoding, final DryResult result) {
        super(new DryResultAction(owner, healthDescriptor, result), defaultEncoding, "DRY");
    }

    /** {@inheritDoc} */
    public MavenAggregatedReport createAggregatedAction(final MavenModuleSetBuild build, final Map<MavenModule, List<MavenBuild>> moduleBuilds) {
        return new DryMavenResultAction(build, getHealthDescriptor(), getDefaultEncoding(),
                new DryResult(build, getDefaultEncoding(), new ParserResult(), false));
    }

    /** {@inheritDoc} */
    public Action getProjectAction(final MavenModuleSet moduleSet) {
        return new DryProjectAction(moduleSet, DryMavenResultAction.class);
    }

    @Override
    public Class<? extends MavenResultAction<DryResult>> getIndividualActionType() {
        return DryMavenResultAction.class;
    }

    @Override
    protected DryResult createResult(final DryResult existingResult, final DryResult additionalResult) {
        return new DryReporterResult(getOwner(), additionalResult.getDefaultEncoding(),
                aggregate(existingResult, additionalResult), existingResult.useOnlyStableBuildsAsReference());
    }
}


/*
 *
 *  Copyright 2015 incode.org
 *
 *
 *  Licensed under the Apache License, Version 2.0 (the
 *  "License"); you may not use this file except in compliance
 *  with the License.  You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 */
package org.incode.module.note.dom.impl.calendarname;

import java.util.Collection;
import java.util.Collections;
import java.util.Set;

import javax.inject.Inject;

import org.apache.isis.applib.annotation.DomainService;
import org.apache.isis.applib.annotation.NatureOfService;
import org.apache.isis.applib.annotation.Programmatic;

import org.incode.module.note.dom.impl.note.Note;
import org.incode.module.note.dom.spi.CalendarNameRepository;

/**
 * Simple wrapper around {@link CalendarNameRepository}, that always returns a non-null list (including
 * the {@link #DEFAULT_CALENDAR_NAME default name} if necessary).
 */
@DomainService(
        nature = NatureOfService.DOMAIN
)
public class CalendarNameService {

    public static final String DEFAULT_CALENDAR_NAME = "(default)";

    /**
     * Return the list of objects to act as calendars for the {@link Note}s to attach to the specified "notable"
     * domain object, as per {@link CalendarNameRepository}, or a default name otherwise.
     *
     * <p>
     *     May return null if there are none (in which case a default name will be used).
     * </p>
     */
    @Programmatic
    public Collection<String> calendarNamesFor(final Object notable) {
        final Set<String> fallback = Collections.singleton(DEFAULT_CALENDAR_NAME);
        if(calendarNameRepository == null) {
            return fallback;
        }
        final Collection<String> calendarNames = calendarNameRepository.calendarNamesFor(notable);
        return calendarNames != null? calendarNames: fallback;
    }

    @Inject
    CalendarNameRepository calendarNameRepository;

}


/**
 * Copyright (C) 2012 Ness Computing, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.nesscomputing.migratory.loader;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Collection;

import com.google.common.base.Charsets;
import com.google.common.io.Resources;

import com.nesscomputing.migratory.MigratoryException;
import com.nesscomputing.migratory.MigratoryException.Reason;

/**
 * Loads a file from the classpath.
 */
public class ClasspathLoader implements MigrationLoader
{
    private final LoaderManager loaderManager;

    public ClasspathLoader(final LoaderManager loaderManager)
    {
        this.loaderManager = loaderManager;
    }

    @Override
    public boolean accept(final URI uri)
    {
        return uri != null && "classpath".equals(uri.getScheme());
    }

    @Override
    public Collection<URI> loadFolder(final URI folderUri, final String pattern)
    {
        try {
            final URI uriLocation = Resources.getResource(this.getClass(), folderUri.getPath()).toURI();
            return loaderManager.loadFolder(uriLocation, pattern);
        }
        catch (URISyntaxException e) {
            throw new MigratoryException(Reason.INTERNAL, e);
        }
    }

    /**
     * This method loads a file from a classpath:/... URI.
     */
    @Override
    public String loadFile(final URI fileUri)
    {
        try {
            final URL urlLocation = Resources.getResource(this.getClass(), fileUri.getPath());
            return Resources.toString(urlLocation, Charsets.UTF_8);
        }
        catch (IOException e) {
            throw new MigratoryException(Reason.INTERNAL, e);
        }
    }
}


/**
 * Copyright (C) 2012 Ness Computing, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.nesscomputing.migratory.loader;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Collection;
import java.util.regex.Pattern;

import javax.annotation.Nullable;

import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.google.common.io.Files;
import com.google.common.io.PatternFilenameFilter;

import com.nesscomputing.migratory.MigratoryException;
import com.nesscomputing.migratory.MigratoryException.Reason;

/**
 * Loads arbitrary files from a file: URI.
 */
public class FileLoader implements MigrationLoader
{
    public static final Function<File, URI> FILE_TO_URL = new Function<File, URI>() {
        @Override
        public URI apply(@Nullable final File file) {
            return file == null ? null : file.toURI();
        }
    };

    private final Charset charset;

    public FileLoader(final Charset charset)
    {
        this.charset = charset;
    }

    @Override
    public boolean accept(final URI uri)
    {
        return uri != null && "file".equals(uri.getScheme());
    }

    @Override
    public Collection<URI> loadFolder(final URI folderUri, final String searchPattern)
    {
        final Pattern pattern = (searchPattern == null) ? null : Pattern.compile(searchPattern);

        final File folderLocation = new File(folderUri);
        if (folderLocation.exists() && folderLocation.canRead()) {
            if (folderLocation.isDirectory()) {
                final File [] files = (pattern == null) ? folderLocation.listFiles() : folderLocation.listFiles(new PatternFilenameFilter(pattern));
                return Collections2.transform(Arrays.asList(files), FILE_TO_URL);
            }
            else {
                throw new MigratoryException(Reason.INTERNAL, "%s is not a directory!", folderUri);
            }
        }
        else {
                throw new MigratoryException(Reason.INTERNAL, "Can not access %s!", folderUri);
        }
    }

    /**
     * This method loads a file from a file:/... URI. This is probably not what you are looking for.
     */
    @Override
    public String loadFile(final URI fileUri) throws IOException
    {
        final File fileLocation = new File(fileUri);
        if (fileLocation.exists() && fileLocation.canRead()) {
            if (fileLocation.isFile()) {
                return Files.toString(fileLocation, charset);
            }
            else {
                throw new MigratoryException(Reason.INTERNAL, "%s is not a file!", fileLocation);
            }
        }
        else {
            throw new MigratoryException(Reason.INTERNAL, "Can not access %s!", fileLocation);
        }
    }
}


/*******************************************************************************
 *
 * Copyright (C) 2015 Mytech Ingenieria Aplicada <http://www.mytechia.com>
 * Copyright (C) 2015 Alejandro Paz <alejandropl@lagostelle.com>
 *
 * This file is part of Vineyard.
 *
 * Vineyard is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 *
 * Vineyard 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 Affero General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Vineyard. If not, see <http://www.gnu.org/licenses/>.
 *
 ******************************************************************************/

package com.hi3project.vineyard.comm.broker;

import com.hi3project.broccoli.bsdm.api.IServiceDescription;
import com.hi3project.broccoli.bsdm.api.asyncronous.IChannelConsumer;
import com.hi3project.broccoli.bsdm.api.asyncronous.IMessageBroker;
import com.hi3project.broccoli.bsdf.api.deployment.container.IBSDMServiceContainer;
import com.hi3project.broccoli.bsdm.api.grounding.IServiceGrounding;
import com.hi3project.broccoli.bsdm.impl.grounding.AsyncMessageServiceGrounding;
import com.hi3project.vineyard.comm.jms.channel.AbstractJMSChannelConsumer;
import com.hi3project.vineyard.comm.stomp.channel.AbstractStompChannelConsumer;
import com.hi3project.broccoli.bsdf.exceptions.MessageBrokerException;
import com.hi3project.broccoli.bsdm.impl.exceptions.ServiceGroundingException;
import com.hi3project.broccoli.io.BSDFLogger;
import com.hi3project.vineyard.registry.client.BrokerConnectorsConfig;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.apache.activemq.broker.BrokerService;
import org.apache.activemq.broker.TransportConnector;

/**
 *

 * Description:
 * A message broker for BSDF services based on ActiveMQ BrokerService, and
 * AsyncMessageServiceGrounding. It holds reference to the registered service
 * groundings , and for each one knows an ActiveMQ TransportConnector opened for
 * that service grounding.
 *
 *

 * It also knows all the IChannelConsumer related to the registered service
 * groundings, used to receive messages syncronously.
 *
 *
 *

 * Creation date:
 * 24-06-2014

 *
 *

 * Changelog:
 *

 *
 1 , 24-06-2014 - Initial release

 *

 *
 *
 *
 * @version 1
 */
public class AsyncMessageBroker implements IMessageBroker
{

    private BrokerService broker = null;

    private String name = null;

    private Collection<AsyncMessageServiceGrounding> serviceGroundings = new ArrayList<AsyncMessageServiceGrounding>();
    private Collection<IChannelConsumer> serviceChannelConsumers = new ArrayList<IChannelConsumer>();

    private IBSDMServiceContainer serviceContainer;

    public AsyncMessageBroker(String name)
    {
        BSDFLogger.getLogger().info("Instances an AsyncMessageBroker: " + name);
        this.name = name;
    }

    @Override
    public synchronized void setMainControlChannel(IBSDMServiceContainer serviceContainer) throws MessageBrokerException
    {
        BSDFLogger.getLogger().info("Sets control channer for: " + serviceContainer.toString());
        try
        {
            this.serviceContainer = serviceContainer;
        } catch (Exception ex)
        {
            throw new MessageBrokerException(
                    "Cannot register container connector for: " + serviceContainer.toString(),
                    ex);
        }
    }

    @Override
    public synchronized void start() throws MessageBrokerException
    {
        BSDFLogger.getLogger().info("Starting broker");

        try
        {

            if (null == this.broker)
            {
                this.broker = initBroker(name);
            }

            this.broker.start();

            // each service grounding has a consumer channel that is activated AFTER
            //ServiceBroker has started
            for (AsyncMessageServiceGrounding serviceGrounding : this.serviceGroundings)
            {
                this.serviceChannelConsumers.add(serviceGrounding.activateChannelConsumer());
            }

            // the container channel is also activated
            if (null != this.serviceContainer)
            {
                this.serviceContainer.activateControlChannels();
            }

        } catch (Exception ex)
        {
            throw new MessageBrokerException("Error starting broker: " + this.name, ex);
        }

    }

    @Override
    public synchronized void stop() throws MessageBrokerException
    {
        BSDFLogger.getLogger().info("Stoping broker");

        try
        {
            if (null != this.broker)
            {

                List<TransportConnector> transportConnectors = this.broker.getTransportConnectors();
                for (TransportConnector transportConnector : transportConnectors)
                {
                    transportConnector.stop();
                }

                this.broker.stop();
                this.broker = null;

                serviceGroundings = new ArrayList<AsyncMessageServiceGrounding>();
                serviceChannelConsumers = new ArrayList<IChannelConsumer>();
            }
        } catch (Exception ex)
        {
            throw new MessageBrokerException("Error stoping broker: " + this.name, ex);
        }
    }

    @Override
    public synchronized void restart() throws MessageBrokerException
    {
        this.stop();
        this.setMainControlChannel(this.serviceContainer);
        this.start();
    }

    @Override
    public synchronized void registerService(IServiceDescription serviceDescription) throws MessageBrokerException, ServiceGroundingException
    {
        for (IServiceGrounding grounding : serviceDescription.getGroundings())
        {
            if (grounding instanceof AsyncMessageServiceGrounding)
            {
                AsyncMessageServiceGrounding amsGrounding = (AsyncMessageServiceGrounding) grounding;
                this.serviceGroundings.add(amsGrounding);
            }
        }

    }

    /*
     Set this broker object to receive messages during a given period of time, blocking execution.
     */
    public synchronized void receiveMessagesSyncronously(long ms) throws ServiceGroundingException
    {
        for (IChannelConsumer chConsumer : this.serviceChannelConsumers)
        {
            if (chConsumer instanceof AbstractJMSChannelConsumer)
            {
                AbstractJMSChannelConsumer achConsumer = (AbstractJMSChannelConsumer) chConsumer;
                achConsumer.receiveOrWait(ms);
            }
            if (chConsumer instanceof AbstractStompChannelConsumer)
            {
                AbstractStompChannelConsumer achConsumer = (AbstractStompChannelConsumer) chConsumer;
                achConsumer.receiveOrWait(ms);
            }
        }
    }

    private static BrokerService initBroker(String name) throws Exception
    {
        BrokerService broker = new BrokerService();

        broker.setBrokerName(name);
        broker.setPersistent(false);
        broker.setUseJmx(false);
        broker.setUseShutdownHook(false);

        broker.addConnector(BrokerConnectorsConfig.openWireConnectorURL);
        broker.addConnector(BrokerConnectorsConfig.stompConnectorURL);
        broker.addConnector(BrokerConnectorsConfig.wsConnectorURL);

        return broker;
    }

}