//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6
// See http://java.sun.com/xml/jaxb
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2014.01.23 at 10:11:20 AM CET
//

package com.tibco.xmlns.applicationmanagement;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlElementDecl;
import javax.xml.bind.annotation.XmlRegistry;
import javax.xml.namespace.QName;

/**
 * This object contains factory methods for each
 * Java content interface and Java element interface
 * generated in the com.tibco.xmlns.applicationmanagement package.
 *
An ObjectFactory allows you to programatically
 * construct new instances of the Java representation
 * for XML content. The Java representation of XML
 * content can consist of schema derived interfaces
 * and classes representing the binding of schema
 * type definitions, element declarations and model
 * groups.  Factory methods for each of these are
 * provided in this class.
 *
 */
@XmlRegistry
public class ObjectFactory {

    private final static QName _PerformPolicy_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "performPolicy");
    private final static QName _NameValuePairInteger_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "NameValuePairInteger");
    private final static QName _Container_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "container");
    private final static QName _Machine_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "machine");
    private final static QName _FormFlow_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "formFlow");
    private final static QName _HttpRepoInstance_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "httpRepoInstance");
    private final static QName _EmailAction_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "emailAction");
    private final static QName _Action_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "action");
    private final static QName _NameValuePairBoolean_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "NameValuePairBoolean");
    private final static QName _RemoteRepoInstance_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "remoteRepoInstance");
    private final static QName _Level_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "level");
    private final static QName _Event_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "event");
    private final static QName _Bw_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "bw");
    private final static QName _NVPair_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "NVPair");
    private final static QName _FailureEvent_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "failureEvent");
    private final static QName _SuspendProcessEvent_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "suspendProcessEvent");
    private final static QName _CustomAction_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "customAction");
    private final static QName _Service_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "service");
    private final static QName _CheckPointRecoveryStorage_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "checkPointRecoveryStorage");
    private final static QName _LogEvent_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "logEvent");
    private final static QName _Checkpoint_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "checkpoint");
    private final static QName _Im_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "im");
    private final static QName _Adapter_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "adapter");
    private final static QName _NameValuePair_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "NameValuePair");
    private final static QName _BaseService_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "baseService");
    private final static QName _RvRepoInstance_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "rvRepoInstance");
    private final static QName _Application_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "application");
    private final static QName _IsFt_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "isFt");
    private final static QName _NameValuePairPassword_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "NameValuePairPassword");
    private final static QName _LocalRepoInstance_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "localRepoInstance");
    private final static QName _RepoInstance_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "repoInstance");
    private final static QName _StartupType_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "startupType");
    private final static QName _AlertAction_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "alertAction");
    private final static QName _PluginsExtends_QNAME = new QName("http://www.tibco.com/xmlns/ApplicationManagement", "extends");

    /**
     * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: com.tibco.xmlns.applicationmanagement
     *
     */
    public ObjectFactory() {
    }

    /**
     * Create an instance of {@link Authentications }
     *
     */
    public Authentications createAuthentications() {
        return new Authentications();
    }

    /**
     * Create an instance of {@link Service }
     *
     */
    public Service createService() {
        return new Service();
    }

    /**
     * Create an instance of {@link NVPairs }
     *
     */
    public NVPairs createNVPairs() {
        return new NVPairs();
    }

    /**
     * Create an instance of {@link ApplicationType }
     *
     */
    public ApplicationType createApplicationType() {
        return new ApplicationType();
    }

    /**
     * Create an instance of {@link ActionType }
     *
     */
    public ActionType createActionType() {
        return new ActionType();
    }

    /**
     * Create an instance of {@link Events }
     *
     */
    public Events createEvents() {
        return new Events();
    }

    /**
     * Create an instance of {@link FaultTolerant }
     *
     */
    public FaultTolerant createFaultTolerant() {
        return new FaultTolerant();
    }

    /**
     * Create an instance of {@link NVPairType }
     *
     */
    public NVPairType createNVPairType() {
        return new NVPairType();
    }

    /**
     * Create an instance of {@link RepoInstances }
     *
     */
    public RepoInstances createRepoInstances() {
        return new RepoInstances();
    }

    /**
     * Create an instance of {@link EmailAction }
     *
     */
    public EmailAction createEmailAction() {
        return new EmailAction();
    }

    /**
     * Create an instance of {@link FailureEvent }
     *
     */
    public FailureEvent createFailureEvent() {
        return new FailureEvent();
    }

    /**
     * Create an instance of {@link AnyObject }
     *
     */
    public AnyObject createAnyObject() {
        return new AnyObject();
    }

    /**
     * Create an instance of {@link Im }
     *
     */
    public Im createIm() {
        return new Im();
    }

    /**
     * Create an instance of {@link NameValuePair }
     *
     */
    public NameValuePair createNameValuePair() {
        return new NameValuePair();
    }

    /**
     * Create an instance of {@link Monitor }
     *
     */
    public Monitor createMonitor() {
        return new Monitor();
    }

    /**
     * Create an instance of {@link NameValuePairPassword }
     *
     */
    public NameValuePairPassword createNameValuePairPassword() {
        return new NameValuePairPassword();
    }

    /**
     * Create an instance of {@link Services }
     *
     */
    public Services createServices() {
        return new Services();
    }

    /**
     * Create an instance of {@link Rulebases }
     *
     */
    public Rulebases createRulebases() {
        return new Rulebases();
    }

    /**
     * Create an instance of {@link HttpRepoInstance }
     *
     */
    public HttpRepoInstance createHttpRepoInstance() {
        return new HttpRepoInstance();
    }

    /**
     * Create an instance of {@link Setting.Java }
     *
     */
    public Setting.Java createSettingJava() {
        return new Setting.Java();
    }

    /**
     * Create an instance of {@link Shutdown }
     *
     */
    public Shutdown createShutdown() {
        return new Shutdown();
    }

    /**
     * Create an instance of {@link RepoInstanceType }
     *
     */
    public RepoInstanceType createRepoInstanceType() {
        return new RepoInstanceType();
    }

    /**
     * Create an instance of {@link LogEvent }
     *
     */
    public LogEvent createLogEvent() {
        return new LogEvent();
    }

    /**
     * Create an instance of {@link Setting }
     *
     */
    public Setting createSetting() {
        return new Setting();
    }

    /**
     * Create an instance of {@link Bindings }
     *
     */
    public Bindings createBindings() {
        return new Bindings();
    }

    /**
     * Create an instance of {@link NameValuePairInteger }
     *
     */
    public NameValuePairInteger createNameValuePairInteger() {
        return new NameValuePairInteger();
    }

    /**
     * Create an instance of {@link Bwprocesses }
     *
     */
    public Bwprocesses createBwprocesses() {
        return new Bwprocesses();
    }

    /**
     * Create an instance of {@link RvRepoInstance }
     *
     */
    public RvRepoInstance createRvRepoInstance() {
        return new RvRepoInstance();
    }

    /**
     * Create an instance of {@link ServiceType }
     *
     */
    public ServiceType createServiceType() {
        return new ServiceType();
    }

    /**
     * Create an instance of {@link Rulebases.Rulebase }
     *
     */
    public Rulebases.Rulebase createRulebasesRulebase() {
        return new Rulebases.Rulebase();
    }

    /**
     * Create an instance of {@link Actions }
     *
     */
    public Actions createActions() {
        return new Actions();
    }

    /**
     * Create an instance of {@link CustomAction }
     *
     */
    public CustomAction createCustomAction() {
        return new CustomAction();
    }

    /**
     * Create an instance of {@link BWServiceType }
     *
     */
    public BWServiceType createBWServiceType() {
        return new BWServiceType();
    }

    /**
     * Create an instance of {@link Binding }
     *
     */
    public Binding createBinding() {
        return new Binding();
    }

    /**
     * Create an instance of {@link SuspendProcessEvent }
     *
     */
    public SuspendProcessEvent createSuspendProcessEvent() {
        return new SuspendProcessEvent();
    }

    /**
     * Create an instance of {@link ServiceInstanceType }
     *
     */
    public ServiceInstanceType createServiceInstanceType() {
        return new ServiceInstanceType();
    }

    /**
     * Create an instance of {@link Plugins }
     *
     */
    public Plugins createPlugins() {
        return new Plugins();
    }

    /**
     * Create an instance of {@link Bw }
     *
     */
    public Bw createBw() {
        return new Bw();
    }

    /**
     * Create an instance of {@link EventType }
     *
     */
    public EventType createEventType() {
        return new EventType();
    }

    /**
     * Create an instance of {@link Product }
     *
     */
    public Product createProduct() {
        return new Product();
    }

    /**
     * Create an instance of {@link NameValuePairBoolean }
     *
     */
    public NameValuePairBoolean createNameValuePairBoolean() {
        return new NameValuePairBoolean();
    }

    /**
     * Create an instance of {@link LocalRepoInstance }
     *
     */
    public LocalRepoInstance createLocalRepoInstance() {
        return new LocalRepoInstance();
    }

    /**
     * Create an instance of {@link Adapter }
     *
     */
    public Adapter createAdapter() {
        return new Adapter();
    }

    /**
     * Create an instance of {@link Bwprocess }
     *
     */
    public Bwprocess createBwprocess() {
        return new Bwprocess();
    }

    /**
     * Create an instance of {@link Checkpoints }
     *
     */
    public Checkpoints createCheckpoints() {
        return new Checkpoints();
    }

    /**
     * Create an instance of {@link RemoteRepoInstanceType }
     *
     */
    public RemoteRepoInstanceType createRemoteRepoInstanceType() {
        return new RemoteRepoInstanceType();
    }

    /**
     * Create an instance of {@link FormFlow }
     *
     */
    public FormFlow createFormFlow() {
        return new FormFlow();
    }

    /**
     * Create an instance of {@link Setting.NTService }
     *
     */
    public Setting.NTService createSettingNTService() {
        return new Setting.NTService();
    }

    /**
     * Create an instance of {@link AlertAction }
     *
     */
    public AlertAction createAlertAction() {
        return new AlertAction();
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "performPolicy")
    public JAXBElement<String> createPerformPolicy(String value) {
        return new JAXBElement<String>(_PerformPolicy_QNAME, String.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link NameValuePairInteger }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "NameValuePairInteger", substitutionHeadNamespace = "http://www.tibco.com/xmlns/ApplicationManagement", substitutionHeadName = "NVPair")
    public JAXBElement<NameValuePairInteger> createNameValuePairInteger(NameValuePairInteger value) {
        return new JAXBElement<NameValuePairInteger>(_NameValuePairInteger_QNAME, NameValuePairInteger.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "container")
    public JAXBElement<String> createContainer(String value) {
        return new JAXBElement<String>(_Container_QNAME, String.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "machine")
    public JAXBElement<String> createMachine(String value) {
        return new JAXBElement<String>(_Machine_QNAME, String.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link FormFlow }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "formFlow", substitutionHeadNamespace = "http://www.tibco.com/xmlns/ApplicationManagement", substitutionHeadName = "baseService")
    public JAXBElement<FormFlow> createFormFlow(FormFlow value) {
        return new JAXBElement<FormFlow>(_FormFlow_QNAME, FormFlow.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link HttpRepoInstance }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "httpRepoInstance", substitutionHeadNamespace = "http://www.tibco.com/xmlns/ApplicationManagement", substitutionHeadName = "remoteRepoInstance")
    public JAXBElement<HttpRepoInstance> createHttpRepoInstance(HttpRepoInstance value) {
        return new JAXBElement<HttpRepoInstance>(_HttpRepoInstance_QNAME, HttpRepoInstance.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link EmailAction }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "emailAction", substitutionHeadNamespace = "http://www.tibco.com/xmlns/ApplicationManagement", substitutionHeadName = "action")
    public JAXBElement<EmailAction> createEmailAction(EmailAction value) {
        return new JAXBElement<EmailAction>(_EmailAction_QNAME, EmailAction.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link ActionType }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "action")
    public JAXBElement<ActionType> createAction(ActionType value) {
        return new JAXBElement<ActionType>(_Action_QNAME, ActionType.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link NameValuePairBoolean }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "NameValuePairBoolean", substitutionHeadNamespace = "http://www.tibco.com/xmlns/ApplicationManagement", substitutionHeadName = "NVPair")
    public JAXBElement<NameValuePairBoolean> createNameValuePairBoolean(NameValuePairBoolean value) {
        return new JAXBElement<NameValuePairBoolean>(_NameValuePairBoolean_QNAME, NameValuePairBoolean.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link RemoteRepoInstanceType }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "remoteRepoInstance")
    public JAXBElement<RemoteRepoInstanceType> createRemoteRepoInstance(RemoteRepoInstanceType value) {
        return new JAXBElement<RemoteRepoInstanceType>(_RemoteRepoInstance_QNAME, RemoteRepoInstanceType.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "level")
    public JAXBElement<String> createLevel(String value) {
        return new JAXBElement<String>(_Level_QNAME, String.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link EventType }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "event")
    public JAXBElement<EventType> createEvent(EventType value) {
        return new JAXBElement<EventType>(_Event_QNAME, EventType.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Bw }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "bw", substitutionHeadNamespace = "http://www.tibco.com/xmlns/ApplicationManagement", substitutionHeadName = "baseService")
    public JAXBElement<Bw> createBw(Bw value) {
        return new JAXBElement<Bw>(_Bw_QNAME, Bw.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link NVPairType }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "NVPair")
    public JAXBElement<NVPairType> createNVPair(NVPairType value) {
        return new JAXBElement<NVPairType>(_NVPair_QNAME, NVPairType.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link FailureEvent }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "failureEvent", substitutionHeadNamespace = "http://www.tibco.com/xmlns/ApplicationManagement", substitutionHeadName = "event")
    public JAXBElement<FailureEvent> createFailureEvent(FailureEvent value) {
        return new JAXBElement<FailureEvent>(_FailureEvent_QNAME, FailureEvent.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link SuspendProcessEvent }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "suspendProcessEvent", substitutionHeadNamespace = "http://www.tibco.com/xmlns/ApplicationManagement", substitutionHeadName = "event")
    public JAXBElement<SuspendProcessEvent> createSuspendProcessEvent(SuspendProcessEvent value) {
        return new JAXBElement<SuspendProcessEvent>(_SuspendProcessEvent_QNAME, SuspendProcessEvent.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link CustomAction }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "customAction", substitutionHeadNamespace = "http://www.tibco.com/xmlns/ApplicationManagement", substitutionHeadName = "action")
    public JAXBElement<CustomAction> createCustomAction(CustomAction value) {
        return new JAXBElement<CustomAction>(_CustomAction_QNAME, CustomAction.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Service }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "service", substitutionHeadNamespace = "http://www.tibco.com/xmlns/ApplicationManagement", substitutionHeadName = "baseService")
    public JAXBElement<Service> createService(Service value) {
        return new JAXBElement<Service>(_Service_QNAME, Service.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Boolean }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "checkPointRecoveryStorage", defaultValue = "false")
    public JAXBElement<Boolean> createCheckPointRecoveryStorage(Boolean value) {
        return new JAXBElement<Boolean>(_CheckPointRecoveryStorage_QNAME, Boolean.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link LogEvent }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "logEvent", substitutionHeadNamespace = "http://www.tibco.com/xmlns/ApplicationManagement", substitutionHeadName = "event")
    public JAXBElement<LogEvent> createLogEvent(LogEvent value) {
        return new JAXBElement<LogEvent>(_LogEvent_QNAME, LogEvent.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "checkpoint")
    public JAXBElement<String> createCheckpoint(String value) {
        return new JAXBElement<String>(_Checkpoint_QNAME, String.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Im }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "im", substitutionHeadNamespace = "http://www.tibco.com/xmlns/ApplicationManagement", substitutionHeadName = "baseService")
    public JAXBElement<Im> createIm(Im value) {
        return new JAXBElement<Im>(_Im_QNAME, Im.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Adapter }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "adapter", substitutionHeadNamespace = "http://www.tibco.com/xmlns/ApplicationManagement", substitutionHeadName = "baseService")
    public JAXBElement<Adapter> createAdapter(Adapter value) {
        return new JAXBElement<Adapter>(_Adapter_QNAME, Adapter.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link NameValuePair }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "NameValuePair", substitutionHeadNamespace = "http://www.tibco.com/xmlns/ApplicationManagement", substitutionHeadName = "NVPair")
    public JAXBElement<NameValuePair> createNameValuePair(NameValuePair value) {
        return new JAXBElement<NameValuePair>(_NameValuePair_QNAME, NameValuePair.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link ServiceType }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "baseService")
    public JAXBElement<ServiceType> createBaseService(ServiceType value) {
        return new JAXBElement<ServiceType>(_BaseService_QNAME, ServiceType.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link RvRepoInstance }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "rvRepoInstance", substitutionHeadNamespace = "http://www.tibco.com/xmlns/ApplicationManagement", substitutionHeadName = "remoteRepoInstance")
    public JAXBElement<RvRepoInstance> createRvRepoInstance(RvRepoInstance value) {
        return new JAXBElement<RvRepoInstance>(_RvRepoInstance_QNAME, RvRepoInstance.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link ApplicationType }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "application")
    public JAXBElement<ApplicationType> createApplication(ApplicationType value) {
        return new JAXBElement<ApplicationType>(_Application_QNAME, ApplicationType.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Boolean }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "isFt")
    public JAXBElement<Boolean> createIsFt(Boolean value) {
        return new JAXBElement<Boolean>(_IsFt_QNAME, Boolean.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link NameValuePairPassword }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "NameValuePairPassword", substitutionHeadNamespace = "http://www.tibco.com/xmlns/ApplicationManagement", substitutionHeadName = "NVPair")
    public JAXBElement<NameValuePairPassword> createNameValuePairPassword(NameValuePairPassword value) {
        return new JAXBElement<NameValuePairPassword>(_NameValuePairPassword_QNAME, NameValuePairPassword.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link LocalRepoInstance }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "localRepoInstance", substitutionHeadNamespace = "http://www.tibco.com/xmlns/ApplicationManagement", substitutionHeadName = "repoInstance")
    public JAXBElement<LocalRepoInstance> createLocalRepoInstance(LocalRepoInstance value) {
        return new JAXBElement<LocalRepoInstance>(_LocalRepoInstance_QNAME, LocalRepoInstance.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link RepoInstanceType }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "repoInstance")
    public JAXBElement<RepoInstanceType> createRepoInstance(RepoInstanceType value) {
        return new JAXBElement<RepoInstanceType>(_RepoInstance_QNAME, RepoInstanceType.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "startupType", defaultValue = "automatic")
    public JAXBElement<String> createStartupType(String value) {
        return new JAXBElement<String>(_StartupType_QNAME, String.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link AlertAction }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "alertAction", substitutionHeadNamespace = "http://www.tibco.com/xmlns/ApplicationManagement", substitutionHeadName = "action")
    public JAXBElement<AlertAction> createAlertAction(AlertAction value) {
        return new JAXBElement<AlertAction>(_AlertAction_QNAME, AlertAction.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link AnyObject }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.tibco.com/xmlns/ApplicationManagement", name = "extends", scope = Plugins.class)
    public JAXBElement<AnyObject> createPluginsExtends(AnyObject value) {
        return new JAXBElement<AnyObject>(_PluginsExtends_QNAME, AnyObject.class, Plugins.class, value);
    }

}


/**
 * (C) Copyright 2011-2015 FastConnect SAS
 * (http://www.fastconnect.fr/) and others.
 *
 * 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 fr.fastconnect.factory.tibco.bw.maven;

import java.io.File;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DefaultArtifact;
import org.apache.maven.artifact.handler.DefaultArtifactHandler;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Parameter;

/**
 *

 * This abstract class is aimed at preparing the build of a TIBCO artefact,
 * either EAR, Projlib, deployment POM, XML configuration file...

 *
 * Because this class inherits from {@link AbstractBWMojo}, a TIBCO environment
 * will be initialized before building the artefact. The created artefact will
 * hence be the same on every platform.
 *

 *
 * @author Mathieu Debove
 *
 */
public abstract class AbstractBWArtifactMojo extends AbstractBWMojo {

    protected final static String WARN_NO_ARTIFACT_ATTACHED  = "Could not attach artifact.";

    /**
     * Whether to skip the compilation of EAR and Projlib.

     *
     * NB: shall be used with 'bw.package.skip', 'maven.install.skip' and
     * 'maven.deploy.skip' set to true.
     */
    @Parameter(property = "bw.compile.skip", required=false, defaultValue="false")
    protected Boolean skipCompile;

    /**
     * Whether to skip the compilation of EAR.

     *
     * NB: shall be used with 'bw.package.skip', 'maven.install.skip' and
     * 'maven.deploy.skip' set to true.
     */
    @Parameter(property = "bw.compile.ear.skip", required=false, defaultValue="false")
    protected Boolean skipEARCompile;

    /**
     * Whether to "touch" the EAR file when EAR compilation is skipped.

     *

     *
     * NB: must be used with 'bw.compile.skip' or 'bw.compile.ear.skip' set to
     * true.
     */
    @Parameter(property = "bw.compile.ear.skip.touch", required=false, defaultValue="false")
    protected Boolean touchEARIfSkipped;

    /**
     * Whether to skip the compilation of Projlib.

     *
     * NB: shall be used with 'bw.package.skip', 'maven.install.skip' and
     * 'maven.deploy.skip' set to true
     */
    @Parameter(property = "bw.compile.projlib.skip", required=false, defaultValue="false")
    protected Boolean skipProjlibCompile;

    /**
     * Whether to "touch" the Projlib file when Projlib compilation is skipped.
     *

     *
     * NB: must be used with 'bw.compile.skip' or 'bw.compile.projlib.skip' set
     * to true.
     */
    @Parameter(property = "bw.compile.projlib.skip.touch", required=false, defaultValue="false")
    protected Boolean touchProjlibIfSkipped;

    /**
     * Whether to skip the package goals.
     *
     * NB: shall be used with 'maven.install.skip' and 'maven.deploy.skip' set
     * to true.
     */
    @Parameter(property = "bw.package.skip", required=false, defaultValue="false")
    protected Boolean skipPackage;

    /**
     * Whether to "touch" the final deployment descriptor file when final
     * deployment descriptor generation is skipped.

     *
     * NB: must be used with 'bw.package.skip'  set to true.
     */
    @Parameter(property = "bw.package.skip.deploy.descriptor.final.touch", required=false, defaultValue="false")
    protected Boolean touchFinalDeploymentDescriptorIfSkipped;

    /**
     * Name of the generated artifact (without file extension).
     */
    @Parameter(property = "project.build.finalName", required = true)
    protected String finalName;

    protected abstract String getArtifactFileExtension(); // abstract because it can be ".ear", ".projlib", ".xml", ".pom" ...

    @Parameter(property = "project.build.classifier")
    protected String classifier;

    /**
     * This returns a {@link DefaultArtifact} object with the same groupId,
     * artifactId, version and scope as the main artifact of the project
     * (for instance 'bw-ear' or 'projlib').
     *
     * This {@link DefaultArtifact} will have its own {@link type} and
     * {@link classifier}.
     *
     * @param a
     * @param type
     * @param classifier
     * @return
     */
	private Artifact extractArtifact(Artifact a, String type, String classifier) {
		if (a == null) {
			return a;
		}

		Artifact result = new DefaultArtifact(a.getGroupId(),
				                              a.getArtifactId(),
				                              a.getVersionRange(),
				                              a.getScope(),
				                              type,
				                              classifier,
				                              new DefaultArtifactHandler(type));

		return result;
	}

	protected void attachFile(File f, String type, String classifier) {
		Artifact artifact = extractArtifact(getProject().getArtifact(), type, classifier);
		artifact.setFile(f);
		getProject().addAttachedArtifact(artifact);
	}

    /**
     * Retrieves the full path of the artifact that will be created.
     *
     * @param basedir, the directory where the artifact will be created
     * @param finalName, the name of the artifact, without file extension
     * @param classifier
     * @return a {@link File} object with the path of the artifact
     */
    protected File getArtifactFile(File basedir, String finalName, String classifier) {
        if (classifier == null) {
            classifier = "";
        } else if (classifier.trim().length() > 0 && !classifier.startsWith("-")) {
            classifier = "-" + classifier;
        }

        return new File(basedir, finalName + classifier + getArtifactFileExtension());
    }

    /**
     * @return the Maven artefact as a {@link File}
     */
    protected File getOutputFile() {
        return getArtifactFile(outputDirectory, finalName, classifier);
    }

    /**
     * This will check whether {@code outputDirectory} exists and is a
     * directory. Otherwise it will be created.
     */
    protected void checkOutputDirectory() {
        if (!outputDirectory.exists() || !outputDirectory.isDirectory()) {
            outputDirectory.mkdirs();
        }
    }

    public void execute() throws MojoExecutionException {
        super.execute();

        getOutputFile().getParentFile().mkdir(); // create output directory
    }

}


/**
 * (C) Copyright 2011-2015 FastConnect SAS
 * (http://www.fastconnect.fr/) and others.
 *
 * 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 fr.fastconnect.factory.tibco.bw.javaxpath;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;

import javax.xml.bind.DatatypeConverter;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;

/**
 * Goal which updates .javaxpath resources in the BW project.
 *
 * @author Emilien THOMAS
 */
@Mojo(defaultPhase = LifecyclePhase.GENERATE_SOURCES, name = "generate", requiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME)
public class XPathResourceBuilderMojo extends AbstractMojo {

	@Parameter(required = true)
	private List<XPathResource> resources;

	protected void classBytesToBWJavaXPath(final XPathResource r)
			throws IOException {
		// Extract byte64 encoding of the .class content
		byte[] bytesForClass = getBytesForClass(r.getClassName());
		String base64 = DatatypeConverter.printBase64Binary(bytesForClass);
		String fileContent = extractFileContent(r.getResourceName());

		String newFileContent;
		// Replace in the extracted file content
		if (fileContent.contains("bytecode>")) {
			newFileContent = fileContent.replaceFirst(
					"(bytecode>)([^<]*)([<])", "$1" + base64 + "$3");
		} else {
			newFileContent = fileContent.replaceFirst("(</)([^:]+):(java-xpath)",
					"<$2:bytecode>" + base64 + "</$2:bytecode></$2:java-xpath");
		}
		// Overwrite the file
		final FileWriter fileWriter = new FileWriter(r.getResourceName(), false);
		try {
			fileWriter.write(newFileContent);
		} finally {
			fileWriter.close();
		}
	}

	/**
	 * MOJO execution method.
	 */
	public void execute() throws MojoExecutionException {

		if (this.resources.size() == 0) {
			throw new MojoExecutionException("No resources configured");
		}

		// Prefered to count error instead of failing on the first one.
		int errCount = 0;

		// Iterate on all configured resources.
		for (final XPathResource r : this.resources) {
			try {
				classBytesToBWJavaXPath(r);
			} catch (Exception e) {
				super.getLog().error(e);
				errCount++;
			}
		}
		if (errCount > 0) {
			throw new MojoExecutionException("There was " + errCount
					+ " error(s) during goal execution, check above.");
		}
	}

	/**
	 * Reads the complete content of the javaxpath file.
	 *
	 * @param filename
	 * @return
	 * @throws IOException
	 */
	protected String extractFileContent(final String filename)
			throws IOException {
		final StringBuilder sb = new StringBuilder();
		String temp = "";
		final BufferedReader bufferedReader = new BufferedReader(
				new FileReader(filename));
		try {
			while (temp != null) {
				temp = bufferedReader.readLine();
				if (temp != null) {
					sb.append(temp);
				}
			}
			return sb.toString();
		} finally {
			bufferedReader.close();
		}
	}

	/**
	 * Reads a class byte code from current {@link ClassLoader}
	 *
	 * @param className
	 * @return
	 * @throws RuntimeException
	 */
	protected byte[] getBytesForClass(final String className)
			throws RuntimeException {
		try {
			ClassLoader classLoader = this.getClass().getClassLoader();
			InputStream stream = classLoader.getResourceAsStream(className
					.replace(".", "/") + ".class");
			if (stream == null) {
				throw new NullPointerException("Class " + className
						+ " could not be loaded. Check plugin dependencies.");
			}
			byte[] byteArray = new byte[1024000];
			int readBytes = 0;
			int currentOffset = 0;
			while ((readBytes = stream.read(byteArray, currentOffset, 1024)) >= 0) {
				currentOffset += readBytes;
			}
			return Arrays.copyOf(byteArray, currentOffset);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}

	}
}


/**
 * (C) Copyright 2011-2015 FastConnect SAS
 * (http://www.fastconnect.fr/) and others.
 *
 * 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 fr.fastconnect.factory.tibco.bw.maven.deployment;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Parameter;

import fr.fastconnect.factory.tibco.bw.maven.compile.CompileEARMojo;
import fr.fastconnect.factory.tibco.bw.maven.packaging.AbstractPackagingMojo;

/**
 *

 * This class inherits from {@link CompileEARMojo} because it will use the
 * EAR generated by this class to deploy it on a TIBCO domain.
 *

 *
 * @author Mathieu Debove
 *
 */
public abstract class AbstractBWDeployMojo extends AbstractPackagingMojo {

	/**
	 * Name of the project once deployed in TIBCO domain
	 */
	@Parameter ( property = deployedProjectNameProperty, required = true )
	protected String deployedProjectName;

	/**
	 * TIBCO domain name
	 */
	@Parameter ( property = domainNameProperty, required = true)
	protected String domainName;

	/**
	 * TIBCO domain username
	 */
	@Parameter ( property = domainUsernameProperty, required = true)
	protected String domainUsername;

	/**
	 * TIBCO domain password
	 */
	@Parameter ( property = domainPasswordProperty, required = true)
	protected String domainPassword;

	@Parameter ( property = "forceAppManageGoals", defaultValue = "false" )
	protected Boolean forceAppManageGoals;

	@Override
	protected String getArtifactFileExtension() {
		return BWEAR_EXTENSION;
	}

	public boolean skip() {
		return (super.skip() || !getProject().getPackaging().startsWith(BWEAR_TYPE)) && !forceAppManageGoals; // startsWith to include bw-ear-deploy
	}

	/**
	 *

	 * For each AppManage command a common set of arguments is required (domain,
	 * project name, ...)
	 *

	 *
	 * @return a list with common arguments for AppManage.
	 */
	public ArrayList<String> commonArguments() {
		ArrayList<String> arguments = new ArrayList<String>();

		arguments.add("-app");
		arguments.add(deployedProjectName);
		arguments.add("-domain");
		arguments.add(domainName);
		arguments.add("-user");
		arguments.add(domainUsername);
		arguments.add("-pw");
		arguments.add(domainPassword);

		return arguments;
	}

	public abstract String getInitMessage();
	public abstract String getFailureMessage();
	public abstract void postAction() throws MojoExecutionException;

	public abstract ArrayList<String> arguments();

	public void execute() throws MojoExecutionException {
		if (skip()) {
			getLog().info(SKIPPING);
			return;
		}

		checkAppManage();

		try {
			getLog().info(getInitMessage());

			ArrayList<String> arguments = arguments();

			ArrayList<File> tras = new ArrayList<File>();
			tras.add(tibcoAppManageTRAPath);

			launchTIBCOBinary(tibcoAppManagePath, tras, arguments, directory, getFailureMessage());

			postAction();
		} catch (IOException e) {
			throw new MojoExecutionException(getFailureMessage(), e);
		}
	}

}


/**
 * (C) Copyright 2011-2015 FastConnect SAS
 * (http://www.fastconnect.fr/) and others.
 *
 * 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 fr.fastconnect.factory.tibco.bw.maven.packaging;

import java.io.IOException;
import java.math.BigInteger;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.bind.JAXBException;

import org.apache.commons.io.FileUtils;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;

import com.tibco.xmlns.applicationmanagement.ApplicationType;
import com.tibco.xmlns.applicationmanagement.EncodingType;
import com.tibco.xmlns.applicationmanagement.Events;
import com.tibco.xmlns.applicationmanagement.HttpRepoInstance;
import com.tibco.xmlns.applicationmanagement.LocalRepoInstance;
import com.tibco.xmlns.applicationmanagement.RepoInstances;
import com.tibco.xmlns.applicationmanagement.RepoType;
import com.tibco.xmlns.applicationmanagement.RvRepoInstance;

import fr.fastconnect.factory.tibco.bw.maven.packaging.monitoring.FailureEvent;
import fr.fastconnect.factory.tibco.bw.maven.packaging.monitoring.LogEvent;

/**
 *

 * This goal recreates an XML Deployment Descriptor file from flat properties
 * files generated by
 *
 * bw:generate-properties-from-xml.

 * Any manual modification performed on the properties files will be integrated
 * in the final XML file.
 *

 *

 * A JAXB implementation of the TIBCO ApplicationManagement schema
 * (namespace = "http://www.tibco.com/xmlns/ApplicationManagement")
 * will be used.

 * Refer to {@link ApplicationManagement} class for details.
 *

 *
 * @author Mathieu Debove
 *
 */
@Mojo( name="generate-xml-from-properties",
defaultPhase=LifecyclePhase.PREPARE_PACKAGE )
public class GenerateXMLFromPropertiesMojo extends AbstractPackagingMojo {

	protected static final String FLAT_PATH_SEPARATOR = "/";

	protected static final String APPLICATION_MANAGEMENT_COPY_FAILURE = "Failed to copy the Application Management file from";
	protected static final String APPLICATION_MANAGEMENT_LOAD_FAILURE = "Failed to load the Application Management file in";
	protected static final String PROPERTIES_GLOBAL_VARIABLES_LOAD_FAILURE = "Failed to load the Global Variables Properties file in";
	protected static final String PROPERTIES_SERVICES_LOAD_FAILURE = "Failed to load the Services Properties file in";
	protected static final String APPLICATION_MANAGEMENT_MERGE_FAILURE = "Failed to merge the Properties files in the Application Management file";
	protected static final String APPLICATION_MANAGEMENT_MERGE_SUCCESS = "Successfully merged the Properties in the final XML Deployment Descriptor in";

	private ApplicationManagement application;

	@Override
	protected String getArtifactFileExtension() {
		return XML_EXTENSION;
	}

	/**
	 *

	 * First we will copy the XML file extracted from the EAR to the final file
	 * to be produced after merging all the properties files.
	 *

	 *
	 *

	 * Then we will initialize the {@link ApplicationType} by unmarshalling
	 * this final file.
	 *

	 *
	 * @throws MojoExecutionException
	 */
	private void init() throws MojoExecutionException {
		try {
			FileUtils.copyFile(deploymentDescriptor, deploymentDescriptorFinal);
		} catch (IOException e) {
			throw new MojoExecutionException(APPLICATION_MANAGEMENT_COPY_FAILURE + " '" + deploymentDescriptor + "' to '" + deploymentDescriptorFinal + "'", e);
		}
		try {
			application = new ApplicationManagement(deploymentDescriptorFinal);
		} catch (JAXBException e) {
			throw new MojoExecutionException(APPLICATION_MANAGEMENT_LOAD_FAILURE + " '" + deploymentDescriptorFinal + "'", e);
		}
	}

	/**
	 *

	 * This will merge the Global Variables properties file into the
	 * {@link ApplicationType} object.
	 *

	 *
	 * @throws MojoExecutionException
	 */
	private void mergeGlobalVariables() throws MojoExecutionException {
		Properties propertiesGlobalVariables;
		try {
			propertiesGlobalVariables = loadPropertiesFile(deploymentGlobalVariables);
		} catch (Exception e) {
			throw new MojoExecutionException(PROPERTIES_GLOBAL_VARIABLES_LOAD_FAILURE + " '" + deploymentGlobalVariables + "'", e);
		}

		Enumeration<Object> e = propertiesGlobalVariables.keys();
   		while (e.hasMoreElements()) {
			String key = (String) e.nextElement();
			String value = propertiesGlobalVariables.getProperty(key);

			application.setGlobalVariable(key, value);
		}
	}

	private void mergeServices() throws MojoExecutionException {
		Properties propertiesServices;
		try {
			propertiesServices = loadPropertiesFile(deploymentServices);
		} catch (Exception e) {
			throw new MojoExecutionException(PROPERTIES_SERVICES_LOAD_FAILURE + " '" + deploymentServices + "'", e);
		}

		Pattern patternElements = Pattern.compile("(\\w+(\\[[\\w -\\.\\/?]*\\])?)+");

		Enumeration<Object> e = propertiesServices.keys();
   		while (e.hasMoreElements()) {
			String currentPath = "";

			String key = (String) e.nextElement();
			String value = propertiesServices.getProperty(key);

			Matcher matcherElements;
			Object parent = null;
			while ((matcherElements = patternElements.matcher(key)).find()) {
				String element = matcherElements.group();
				currentPath = currentPath + FLAT_PATH_SEPARATOR + element;

				parent = application.getElement(currentPath, element, value, parent);

				if (key.equals(element)) {
					break;
				}
				key = key.substring(element.length()+1);
			}
		}

		try {
			application.removeDefaultBindingIfNotExists(loadPropertiesFile(deploymentServices));
		} catch (Exception ex) {
			throw new MojoExecutionException(PROPERTIES_SERVICES_LOAD_FAILURE + " '" + deploymentServices + "'", ex);
		}
		application.removeDuplicateBinding();
	}

	/**
	 * This will update the <repoInstances> element.
	 */
	private void updateRepoInstances() {
		RepoInstances repoInstances = application.getRepoInstances();

		RvRepoInstance rvRepoInstance = repoInstances.getRvRepoInstance();
		rvRepoInstance.setDiscoveryTimout(BigInteger.valueOf(repoRvDiscoveryTimeout));
		rvRepoInstance.setTimeout(BigInteger.valueOf(repoRvTimeout));
		rvRepoInstance.setDaemon(repoRvDaemon);
		rvRepoInstance.setService(repoRvService);
		rvRepoInstance.setNetwork(repoRvNetwork);
		rvRepoInstance.setRegionalSubject(repoRvRegionalSubject);
		rvRepoInstance.setOperationRetry(BigInteger.valueOf(repoRvOperationRetry));
		rvRepoInstance.setExtraPropertyFile(repoRvExtraPropertyFile);
		rvRepoInstance.setServer(repoRvServer);
		rvRepoInstance.setUser(repoRvUser);
		rvRepoInstance.setPassword(repoRvPassword);

		HttpRepoInstance httpRepoInstance = repoInstances.getHttpRepoInstance();
		httpRepoInstance.setTimeout(BigInteger.valueOf(repoHttpTimeout));
		httpRepoInstance.setUrl(repoHttpUrl);
		httpRepoInstance.setServer(repoHttpServer);
		httpRepoInstance.setUser(repoHttpUser);
		httpRepoInstance.setPassword(repoHttpPassword);
		httpRepoInstance.setExtraPropertyFile(repoHttpExtraPropertyFile);

		LocalRepoInstance localRepoInstance = repoInstances.getLocalRepoInstance();
		EncodingType encoding;
		try {
			encoding = EncodingType.valueOf(repoLocalEncoding);
		} catch (IllegalArgumentException e) {
			encoding = EncodingType.UTF_8;
		}
		localRepoInstance.setEncoding(encoding);

		repoInstances.setRvRepoInstance(rvRepoInstance);
		repoInstances.setHttpRepoInstance(httpRepoInstance);
		repoInstances.setLocalRepoInstance(localRepoInstance);

		RepoType repoType;
		try {
			repoType = RepoType.valueOf(repoSelectInstance.toUpperCase());
		} catch (IllegalArgumentException e) {
			repoType = RepoType.LOCAL;
		}
		repoInstances.setSelected(repoType);
	}

	private void updateMonitoringRules() {
		Events events = createMonitoringEvents();
		application.addMonitoringEventsToAllServices(events);
	}

	private void updateAdditionalInfo() {
		getLog().debug("Updating additional information...");
		getLog().debug("MaxDeploymentRevision: " + maxDeploymentRevision);
		getLog().debug("Contact: " + contact);
		getLog().debug("Description: " + description);
		application.setMaxDeploymentRevision(maxDeploymentRevision);
		application.setContact(contact);
		application.setDescription(description);
	}

	public void execute() throws MojoExecutionException {
		if (super.skip()) {
           	if (deploymentDescriptorFinal != null && !deploymentDescriptorFinal.exists() && touchFinalDeploymentDescriptorIfSkipped) {
           		// final deployment descriptor was not created because packaging is skipped
           		// however we "touch" the final deployment descriptor file so there is an empty final deployment descriptor file created
           		try {
           			deploymentDescriptorFinal.getParentFile().mkdirs();
           			deploymentDescriptorFinal.createNewFile();
				} catch (IOException e) {
					throw new MojoExecutionException(e.getLocalizedMessage(), e);
				}
           	}

			if (deploymentDescriptorFinal != null && deploymentDescriptorFinal.exists()) {
				attachFile(deploymentDescriptorFinal, XML_TYPE, "final");
			} else {
            	getLog().warn(WARN_NO_ARTIFACT_ATTACHED);
			}

			return;
		}

		init();

		mergeGlobalVariables();
		mergeServices();

		updateRepoInstances();
		updateMonitoringRules();
		updateAdditionalInfo();

		try {
			application.save();
		} catch (JAXBException e) {
			throw new MojoExecutionException(APPLICATION_MANAGEMENT_MERGE_FAILURE + " '" + deploymentServices + "'", e);
		}

		attachFile(deploymentDescriptorFinal, XML_TYPE, "final");

		getLog().info(APPLICATION_MANAGEMENT_MERGE_SUCCESS + " '" + deploymentDescriptorFinal + "'");
	}

	private Events createMonitoringEvents() {
		Events result = new Events();

		if (events != null) {
			List<FailureEvent> failures = events.getFailures();
			if (failures != null) {
				for (FailureEvent failureEvent : failures) {
					ApplicationManagement.addEvent(result, failureEvent);
				}
			}
			List<LogEvent> logs = events.getLogs();
			if (logs != null) {
				for (LogEvent logEvent : logs) {
					ApplicationManagement.addEvent(result, logEvent);
				}
			}
		}

		return result;
	}

}


/**
 * (C) Copyright 2011-2015 FastConnect SAS
 * (http://www.fastconnect.fr/) and others.
 *
 * 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 fr.fastconnect.factory.tibco.bw.maven.compile;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.codehaus.mojo.truezip.Fileset;
import org.codehaus.mojo.truezip.TrueZipFileSet;
import org.codehaus.mojo.truezip.internal.DefaultTrueZip;
import org.jaxen.JaxenException;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.jdom.xpath.XPath;

import de.schlichtherle.truezip.file.TArchiveDetector;
import de.schlichtherle.truezip.file.TConfig;
import de.schlichtherle.truezip.file.TFile;
import de.schlichtherle.truezip.fs.archive.zip.ZipDriver;
import de.schlichtherle.truezip.socket.sl.IOPoolLocator;
import fr.fastconnect.factory.tibco.bw.maven.AbstractBWArtifactMojo;

/**
 *

 * This goal includes the JAR dependencies of the runtime scope inside the
 * "lib.zip" of the TIBCO BusinessWorks EAR.

 * It allows to load seamlessly the transitive dependencies of JARs of the
 * TIBCO BusinessWorks project and avoid the ClassNotFoundException issues when
 * the application is deployed on a TIBCO domain.
 *

 *

 * This step can be ignored by setting includeTransitiveJARsInEAR to
 * false.
 *

 *
 * @see UpdateAliasesLibsMojo
 * @author Mathieu Debove
 *
 */
@Mojo( name="include-dependencies-in-bw-ear",
defaultPhase=LifecyclePhase.COMPILE )
public class IncludeDependenciesInEARMojo extends AbstractBWArtifactMojo {

	/**
	 * Whether to add JARs files inside EAR.
	 */
	@Parameter (property="includeTransitiveJARsInEAR", defaultValue="true")
	public Boolean includeTransitiveJARsInEAR;

	/**
	 * Whether to rename JARs files inside EAR without their version.
	 */
	@Parameter (property="removeVersionFromFileNames", defaultValue="false")
	public Boolean removeVersionFromFileNames;

	@Override
	protected String getArtifactFileExtension() {
		return BWEAR_EXTENSION;
	}

	private DefaultTrueZip truezip;

	/**
	 *

	 * This methods copies the transitive JAR dependencies of the project inside
	 * the "WEB-INF/lib" folder of the "lib.zip" subarchive of the TIBCO
	 * BusinessWorks EAR archive.
	 *

	 *
	 * @param ear, the TIBCO BusinessWorks EAR archive file
	 * @throws IOException
	 * @throws JDOMException
	 * @throws JaxenException
	 */
	private void copyRuntimeJARsInEAR(File ear) throws IOException, JDOMException {
		Fileset fileSet = new Fileset();
		fileSet.setDirectory(buildLibDirectory.getAbsolutePath());

		for (Dependency dependency : this.getJarDependencies()) {
			String jarName = getJarName(dependency, false);

			fileSet.addInclude(jarName); // using jarName because files are all in buildLibDirectory
		}

		String ouptutDirectory = ear.getAbsolutePath() + File.separator + "lib.zip" + File.separator + "WEB-INF" + File.separator + "lib";
        fileSet.setOutputDirectory(ouptutDirectory);

        if (fileSet.getIncludes() != null && !fileSet.getIncludes().isEmpty()) {
        	truezip.copy(fileSet);
        }
		truezip.sync();

		if (removeVersionFromFileNames) {
			removeVersionFromFileNames(ouptutDirectory, ear);

			truezip.sync();
		}
	}

	private void removeVersionFromFileNames(String ouptutDirectory, File ear) throws IOException, JDOMException {
		for (Dependency dependency : this.getJarDependencies()) {
			Pattern p = Pattern.compile("(.*)-" + dependency.getVersion() + JAR_EXTENSION);

			String includeOrigin = getJarName(dependency, false);
			String includeDestination;

			Matcher m = p.matcher(includeOrigin);
			if (m.matches()) {
				includeDestination = m.group(1)+JAR_EXTENSION;

				truezip.moveFile(new TFile(ouptutDirectory + File.separator + includeOrigin), new TFile(ouptutDirectory + File.separator + includeDestination));

				updateAlias(includeOrigin, includeDestination, ear);
			}
		}

		truezip.sync();
	}

	private void updateAlias(String includeOrigin, String includeDestination, File ear) throws JDOMException, IOException, JDOMException {
		TFile xmlTIBCO = new TFile(ear.getAbsolutePath() + File.separator + "TIBCO.xml");
		String tempPath = ear.getParentFile().getAbsolutePath() + File.separator + "TIBCO.xml";
		TFile xmlTIBCOTemp = new TFile(tempPath);

		truezip.copyFile(xmlTIBCO, xmlTIBCOTemp);

		File xmlTIBCOFile = new File(tempPath);

		SAXBuilder sxb = new SAXBuilder();
		Document document = sxb.build(xmlTIBCOFile);

		XPath xpa = XPath.newInstance("//dd:NameValuePairs/dd:NameValuePair[starts-with(dd:name, 'tibco.alias') and dd:value='" + includeOrigin + "']/dd:value");
		xpa.addNamespace("dd", "http://www.tibco.com/xmlns/dd");

		Element singleNode = (Element) xpa.selectSingleNode(document);
		if (singleNode != null) {
			singleNode.setText(includeDestination);
			XMLOutputter xmlOutput = new XMLOutputter();
			xmlOutput.setFormat(Format.getPrettyFormat().setIndent("    "));
			xmlOutput.output(document, new FileWriter(xmlTIBCOFile));

			truezip.copyFile(xmlTIBCOTemp, xmlTIBCO);
		}

		updateAliasInPARs(includeOrigin, includeDestination, ear);
	}

	private void updateAliasInPARs(String includeOrigin, String includeDestination, File ear) throws IOException, JDOMException {
		TrueZipFileSet pars = new TrueZipFileSet();
		pars.setDirectory(ear.getAbsolutePath());
		pars.addInclude("*.par");
		List<TFile> parsXML = truezip.list(pars);
		for (TFile parXML : parsXML) {
			TFile xmlTIBCO = new TFile(parXML, "TIBCO.xml");

			String tempPath = ear.getParentFile().getAbsolutePath() + File.separator + "TIBCO.xml";
			TFile xmlTIBCOTemp = new TFile(tempPath);

			truezip.copyFile(xmlTIBCO, xmlTIBCOTemp);

			File xmlTIBCOFile = new File(tempPath);

			SAXBuilder sxb = new SAXBuilder();
			Document document = sxb.build(xmlTIBCOFile);

			XPath xpa = XPath.newInstance("//dd:NameValuePairs/dd:NameValuePair[dd:name='EXTERNAL_JAR_DEPENDENCY']/dd:value");
			xpa.addNamespace("dd", "http://www.tibco.com/xmlns/dd");

			Element singleNode = (Element) xpa.selectSingleNode(document);
			if (singleNode != null) {
				String value = singleNode.getText().replace(includeOrigin, includeDestination);
				singleNode.setText(value);
				XMLOutputter xmlOutput = new XMLOutputter();
				xmlOutput.setFormat(Format.getPrettyFormat().setIndent("    "));
				xmlOutput.output(document, new FileWriter(xmlTIBCOFile));

				truezip.copyFile(xmlTIBCOTemp, xmlTIBCO);
			}
		}
	}

	public void execute() throws MojoExecutionException {
    	if (skipCompile || skipEARCompile) {
    		getLog().info(SKIPPING);
    		return;
    	}

		if (isCurrentGoal("bw:launch-designer") || !includeTransitiveJARsInEAR) {
			return; // ignore
		}

		super.execute();

		File ear = getProject().getArtifact().getFile(); // EAR generated by "compile-bw-ear" goal
		if (ear == null) {
			ear = getOutputFile();
		}
		getLog().debug("Using EAR : " + ear.getAbsolutePath());

		TConfig.get().setArchiveDetector( new TArchiveDetector( TArchiveDetector.NULL, new Object[][] {
				{ "zip|kar|par|ear", new ZipDriver( IOPoolLocator.SINGLETON ) },
		} ) );

		truezip = new DefaultTrueZip();

		try {
			this.copyRuntimeJARsInEAR(ear);
		} catch (IOException e) {
			throw new MojoExecutionException(e.getMessage(), e);
		} catch (JDOMException e) {
			throw new MojoExecutionException(e.getMessage(), e);
		}
	}

}


/**
 * (C) Copyright 2011-2015 FastConnect SAS
 * (http://www.fastconnect.fr/) and others.
 *
 * 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 fr.fastconnect.factory.tibco.bw.maven.source;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Pattern;

import org.apache.commons.io.FilenameUtils;
import org.apache.maven.model.FileSet;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugins.annotations.Parameter;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;

/**
 *

 * This is the base class to define a list of projects. The list will be
 * populating according to several criteria such as {@code workspaceRoot}
 * (directory where to look for the projects) or the type of project defined by
 * concrete children classes of inner-class {@link AbstractProject}.
 *

 *
 * @author Mathieu Debove
 *
 */
public abstract class AbstractProjectsListMojo extends AbstractMojo {

	/**
	 *

	 * A project can be either:
	 *

	 *
an existing Maven project defined by a POM

	 *
an existing BW project that is to be mavenized (Maven properties such
	 * as groupId, artifactId & version will be guessed from provided values)
	 *

	 *

	 * Concrete inner-classes will define the properties according to these
	 * profiles.
	 *

	 */
	public static abstract class AbstractProject {
		protected Log logger; // Maven logger (because the inner-class must be static)
		private String mandatoryFilename; // the mandatory filename will trigger the add of a project to the projects list
		private File path; // original path of the file that triggered the creation of an AbstractProject
		protected File root; // root path where the projects are searched

		/**
		 * The concrete inner-classes must be instantiated with the default
		 * constructor (with no arguments).
		 * The instantiator is responsible for calling the initialize method
		 * right after the instantiation of concrete inner-class.
		 * @throws XmlPullParserException
		 * @throws IOException
		 */
		public void initialize(File path, File root, HashMap<String, String> m, String mandatoryFilename, Log logger) throws IOException, XmlPullParserException {
			this.logger = logger;
			this.mandatoryFilename = mandatoryFilename;
			this.path = path;
			this.root = root;
		}

		public String getAbsolutePath() {
			return root + File.separator + getRelativePath();
//			return root + File.separator + getOriginalRelativePath();
		}

		public String getOriginalAbsolutePath() {
//			return root + File.separator + getRelativePath();
			return root + File.separator + getOriginalRelativePath();
		}

		public String getMandatoryFilePath() {
			return getOriginalAbsolutePath() + File.separator + mandatoryFilename;
		}

		public String getMandatoryFilePath(String customMandatoryFilename) {
			return getOriginalAbsolutePath() + File.separator + customMandatoryFilename;
		}

		private String _getRelativePath() {
			String s = path.getAbsolutePath();
			s = s.replace(root.getAbsolutePath()+File.separator, "");

			s = s.replace(mandatoryFilename, "");
			if (s.endsWith(File.separator)) {
				s = s.substring(0, s.length()-1);
			}

			return s;
		}
		public String getOriginalRelativePath() {
			return _getRelativePath();
		}

		public String getRelativePath() {
			return _getRelativePath();
		}

		// default is not to ignored (concrete inner-classes can override)
		public boolean isIgnored() {
			return false;
		}

		// information of the project from Maven point-of-view
		public abstract String getProjectName();
		public abstract String getGroupId();
		public abstract String getArtifactId();
		public abstract String getVersion();

		public Boolean getPutPOMInParentDirectory() {
			return false;
		}
	}

	protected final static String PROJECT_FOUND = " project was found.";
	protected final static String PROJECTS_FOUND = " projects were found.";
	protected final static String NOTHING_WAS_PERFORMED = "No action was performed. Add '-DdoIt=true' to perform.";

	/**
	 *  Whether to trigger the action of children classes or not
	 */
	@Parameter ( property = "doIt", required = true, defaultValue = "false" )
	protected boolean doIt;

	/**
	 *  Whether to search recursively in subdirectories or not
	 */
	@Parameter ( property = "recursive", required = false, defaultValue = "true" )
	protected boolean recursive;

	/**
	 *  A list of comma-separated patterns where to search.
	 *  Must be use with 'recursive' switch.
	 *
	 */
	@Parameter ( property = "patterns" )
	protected List<String> patterns;

	/**
	 *  Whether to display the list of projects or not.
	 */
	@Parameter ( property = "display.list", defaultValue = "true" )
	protected boolean displayList;

	/**
	 * This is the main directory where to look for projects.
	 * The projects can be in subfolders.
	 */
	@Parameter ( required = false, property = "workspaceRoot", defaultValue="${basedir}" )
	protected File workspaceRoot;

	protected List<AbstractProject> projects;
	protected FileSet restriction;

    static class PathResolutionException extends RuntimeException {
		private static final long serialVersionUID = 2723212952556555691L;

		PathResolutionException(String msg) {
            super(msg);
        }
    }

    /**
     *

     * Get the relative path from one file to another, specifying the directory
     * separator.
     * If one of the provided resources does not exist, it is assumed to be a
     * file unless it ends with '/' or '\'.
     *

     *
     * @param targetPath targetPath is calculated to this file
     * @param basePath basePath is calculated from this file
     * @param pathSeparator directory separator. The platform default is not assumed so that we can test Unix behaviour when running on Windows (for example)
     * @return
     */
    public static String getRelativePath(String targetPath, String basePath, String pathSeparator) {
        // Normalize the paths
        String normalizedTargetPath = FilenameUtils.normalizeNoEndSeparator(targetPath);
        String normalizedBasePath = FilenameUtils.normalizeNoEndSeparator(basePath);

        // Undo the changes to the separators made by normalization
        if (pathSeparator.equals("/")) {
            normalizedTargetPath = FilenameUtils.separatorsToUnix(normalizedTargetPath);
            normalizedBasePath = FilenameUtils.separatorsToUnix(normalizedBasePath);

        } else if (pathSeparator.equals("\\")) {
            normalizedTargetPath = FilenameUtils.separatorsToWindows(normalizedTargetPath);
            normalizedBasePath = FilenameUtils.separatorsToWindows(normalizedBasePath);

        } else {
            throw new IllegalArgumentException("Unrecognised dir separator '" + pathSeparator + "'");
        }

        String[] base = normalizedBasePath.split(Pattern.quote(pathSeparator));
        String[] target = normalizedTargetPath.split(Pattern.quote(pathSeparator));

        // First get all the common elements. Store them as a string,
        // and also count how many of them there are.
        StringBuffer common = new StringBuffer();

        int commonIndex = 0;
        while (commonIndex < target.length && commonIndex < base.length
                && target[commonIndex].equals(base[commonIndex])) {
            common.append(target[commonIndex] + pathSeparator);
            commonIndex++;
        }

        if (commonIndex == 0) {
            // No single common path element. This most
            // likely indicates differing drive letters, like C: and D:.
            // These paths cannot be relativized.
            throw new PathResolutionException("No common path element found for '" + normalizedTargetPath + "' and '" + normalizedBasePath + "'");
        }

        // The number of directories we have to backtrack depends on whether the base is a file or a dir
        // For example, the relative path from
        //
        // /foo/bar/baz/gg/ff to /foo/bar/baz
        //
        // ".." if ff is a file
        // "../.." if ff is a directory
        //
        // The following is a heuristic to figure out if the base refers to a file or dir. It's not perfect, because
        // the resource referred to by this path may not actually exist, but it's the best I can do
        boolean baseIsFile = true;

        File baseResource = new File(normalizedBasePath);

        if (baseResource.exists()) {
            baseIsFile = baseResource.isFile();

        } else if (basePath.endsWith(pathSeparator)) {
            baseIsFile = false;
        }

        StringBuffer relative = new StringBuffer();

        if (base.length != commonIndex) {
            int numDirsUp = baseIsFile ? base.length - commonIndex - 1 : base.length - commonIndex;

            for (int i = 0; i < numDirsUp; i++) {
                relative.append(".." + pathSeparator);
            }
        }
        relative.append(normalizedTargetPath.substring(common.length()));
        return relative.toString();
    }

    private static String toCommaSeparatedString(List<String> strings) {
        StringBuilder sb = new StringBuilder();
        for (String string : strings) {
            if (sb.length() > 0) {
            	sb.append(", ");
            }
            sb.append(string);
        }
        return sb.toString();
    }

	public static List<File> toFileList(FileSet fileSet) throws IOException {
        File directory = new File(fileSet.getDirectory());
        String includes = toCommaSeparatedString(fileSet.getIncludes());
        String excludes = toCommaSeparatedString(fileSet.getExcludes());
        return FileUtils.getFiles(directory, includes, excludes);
    }

    protected int successfullyPerformedAction;
    protected abstract void displayProject(AbstractProject p);
    protected boolean performAction(AbstractProject p) {
		return true;
	}

	protected abstract void initProjects() throws IOException, InstantiationException, IllegalAccessException, IllegalArgumentException, SecurityException, InvocationTargetException, NoSuchMethodException, XmlPullParserException;

	protected final void initProjects(String mandatoryFilename, HashMap<String, String> m, Class<? extends AbstractProject> classAbstractProject) throws IOException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, NoSuchMethodException, XmlPullParserException {
		projects = new ArrayList<AbstractProject>();

		restriction= new FileSet();
		restriction.setDirectory(workspaceRoot.getAbsolutePath());

		if (recursive) {
			for (String p : patterns) {
				restriction.addInclude(p + mandatoryFilename);
			}
		} else {
			restriction.addInclude(mandatoryFilename); // we are only looking in the "workspaceRoot" directory
		}
		restriction.addExclude("**/target/**/" + mandatoryFilename);
		restriction.addExclude("**/bin/" + mandatoryFilename);

		List<File> files = toFileList(restriction);

		for (File f : files) {
			Constructor<? extends AbstractProject> ctor = classAbstractProject.getConstructor();
			AbstractProject ap = ctor.newInstance();

			ap.initialize(f, workspaceRoot, m, mandatoryFilename, getLog());
			if (!ap.isIgnored()) {
				projects.add(ap);
			} else {
				getLog().debug("Ignoring project '" + ap.getProjectName() + "'");
			}
		}
	}

	protected void browseList(){
		for (AbstractProject p : projects) {
			// display
			if (displayList) {
				getLog().info("---");
				displayProject(p);
				getLog().info("");
			}

			// perform action (if exists)
			if (doIt && performAction(p)) {
				successfullyPerformedAction++;
			}
		}

		getLog().info("");
		if (projects.size()>1) {
			getLog().info(projects.size() + PROJECTS_FOUND);
		} else {
			getLog().info(projects.size() + PROJECT_FOUND);
		}

	}

	public void execute() throws MojoExecutionException, MojoFailureException {
		if (patterns == null || patterns.isEmpty()) {
			patterns = new ArrayList<String>();
			patterns.add("**/");
		}

		if (recursive) {
			getLog().info("Scanning recursively '" + workspaceRoot + "' with patterns '" + patterns.toString() +"'");
		} else {
			getLog().info("Scanning '" + workspaceRoot + "'");
		}

		successfullyPerformedAction = 0;
		try {
			initProjects();
		} catch (Exception e) {
			throw new MojoExecutionException(e.getLocalizedMessage(), e);
		}

		browseList();
	}

}


/**
 * (C) Copyright 2011-2015 FastConnect SAS
 * (http://www.fastconnect.fr/) and others.
 *
 * 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 fr.fastconnect.factory.tibco.bw.maven.packaging;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;

import fr.fastconnect.factory.tibco.bw.maven.packaging.ApplicationManagement.SortedProperties;

/**
 *

 * This goal will merge the reference and common properties into the working
 * properties files (usually the ones in "target/package").
 *

 *
 * @author Mathieu Debove
 *
 */
@Mojo( name="merge-properties",
defaultPhase=LifecyclePhase.PREPARE_PACKAGE )
public class MergePropertiesMojo extends AbstractPackagingMojo {

	/**
	 * By default, the empty binding ("bw[EXAMPLE.par]/bindings/binding[]) is
	 * removed if other named bindings exists
	 * ("bw[EXAMPLE.par]/bindings/binding[named]").
	 * It is possible to keep this empty binding by setting
     * alwaysKeepEmptyBindings to true. Default is false.
	 */
	@Parameter (property = "alwaysKeepEmptyBindings", defaultValue = "false")
	boolean alwaysKeepEmptyBindings;

	/**
	 * It is possible to ignore any merging of properties by setting
	 * ignorePropertiesMerge to true. Default is false
	 * (do merge).
	 */
	@Parameter (property = "ignorePropertiesMerge", defaultValue = "false")
	boolean ignorePropertiesMerge;

	/**
	 * By default the properties from common properties are merged first and the
	 * properties from reference specific to the project last. By setting
	 * mergeCommonLast to true, the common properties are mergerd last.
	 */
	@Parameter (property = "mergeCommonLast", defaultValue = "false")
	boolean mergeCommonLast;

	private enum MergedFiles {
		NONE, GV, SERVICES, BOTH
	}

	protected final static String MERGING_PROPERTIES = "Merging properties...";
	protected final static String NOTHING_TO_MERGE = "Nothing to merge.";
	protected final static String MERGE_FAILURE = "Failed to merge properties";
	protected final static String PROPERTIES_LOAD_FAILURE = "Failed to load properties";

	protected final static String PROPERTIES_SAVE_GVS_SUCCESS = "Successfully saved merged properties to file";
	protected final static String PROPERTIES_SAVE_GVS_FAILURE = "Failed to save merged properties to XML file";
	protected final static String PROPERTIES_SAVE_SERVICES_SUCCESS = "Successfully saved merged properties to file";
	protected final static String PROPERTIES_SAVE_SERVICES_FAILURE = "Failed to save merged properties to XML file";

	protected final static String USING_GVS_COMMON_FILE = "Using Global Variables common properties file";
	protected final static String USING_GVS_REFERENCE_FILE = "Using Global Variables reference properties file";
	protected final static String USING_SERVICES_COMMON_FILE = "Using Services common properties file";
	protected final static String USING_SERVICES_REFERENCE_FILE = "Using Services reference properties file";

	private List<ImmutablePair<String, String>> pairParInstance = new ArrayList<ImmutablePair<String, String>>(); // keep trace of dynamically created bindings (to generate them only once)

	private final static String regexNotEmptyBinding = "^bw\\[(.*)\\]/bindings/binding\\[(.+)\\]/(.*)$";
	private final static String regexEmptyBinding = "^bw\\[(.*)\\]/bindings/binding(\\[\\])/(.*)$";

	@Override
	protected String getArtifactFileExtension() {
		return PROPERTIES_EXTENSION;
	}

	public MergedFiles mergeFiles(Properties propertiesGlobalVariables,
								  Properties propertiesServices,
								  File deploymentGlobalVariables,
								  File deploymentServices,
								  String messageGlobalVariables,
								  String messageServices) throws MojoExecutionException, IOException {

		MergedFiles result = MergedFiles.NONE;

		// Merge with files if they exist
		if (deploymentGlobalVariables != null &&
			deploymentGlobalVariables.exists() &&
			!deploymentGlobalVariables.getCanonicalPath().equals(this.deploymentGlobalVariables.getCanonicalPath())) {
			// FIXME: check the checksum of files instead of canonical path ?
			getLog().info(messageGlobalVariables + " : " + deploymentGlobalVariables.getAbsolutePath());

			Properties propertiesGlobalVariablesReference;
			try {
				propertiesGlobalVariablesReference = loadPropertiesFile(deploymentGlobalVariables);
			} catch (Exception e) {
				throw new MojoExecutionException(PROPERTIES_LOAD_FAILURE, e);
			}

			Enumeration<Object> e = propertiesGlobalVariablesReference.keys();
	   		while (e.hasMoreElements()) {
				String key = (String) e.nextElement();
				String value = propertiesGlobalVariablesReference.getProperty(key);

				propertiesGlobalVariables.setProperty(key, value); // add or override value
			}

			result = MergedFiles.GV;
		}

		Pattern pNotEmptyBinding = Pattern.compile(regexNotEmptyBinding);

		if (deploymentServices != null &&
			deploymentServices.exists() &&
			!deploymentServices.getCanonicalPath().equals(this.deploymentServices.getCanonicalPath())) {
			// FIXME: check the checksum of files instead of canonical path ?

			getLog().info(messageServices + " : " + deploymentServices.getAbsolutePath());
			Properties propertiesServicesReference;
			try {
				propertiesServicesReference = loadPropertiesFile(deploymentServices);
			} catch (Exception e) {
				throw new MojoExecutionException(PROPERTIES_LOAD_FAILURE, e);
			}

			String par, binding;
			Enumeration<Object> e = propertiesServicesReference.keys();
	   		while (e.hasMoreElements()) {
				String key = (String) e.nextElement();

				Matcher mNotEmptyBinding = pNotEmptyBinding.matcher(key);

				if (mNotEmptyBinding.matches() && !isAWildCard(key)) {
					par = mNotEmptyBinding.group(1);
					binding = mNotEmptyBinding.group(2);
					ImmutablePair<String, String> pair = new ImmutablePair<String, String>(par, binding);
					if (!pairParInstance.contains(pair)) {
						propertiesServices = duplicateEmptyBinding(propertiesServices, par, binding);
						pairParInstance.add(pair);
					}
				}

				String value = propertiesServicesReference.getProperty(key);

				propertiesServices.setProperty(key, value); // add or override value
			}

			propertiesServices = expandWildCards(propertiesServices);

			if (result == MergedFiles.GV) {
				result = MergedFiles.BOTH;
			} else {
				result = MergedFiles.SERVICES;
			}
		}

		return result;
	}

	private Properties duplicateEmptyBinding(Properties properties, String par, String binding) {
		String key, value;
		Pattern pEmptyBinding = Pattern.compile(regexEmptyBinding);

		Enumeration<Object> e = properties.keys();
		while (e.hasMoreElements()) {
			key = (String) e.nextElement();
			value = properties.getProperty(key);
			Matcher mEmptyBinding = pEmptyBinding.matcher(key);
			if (mEmptyBinding.matches() && mEmptyBinding.group(1).equals(par)) {
				key = "bw[" + mEmptyBinding.group(1) + "]/bindings/binding[" + binding + "]/" + mEmptyBinding.group(3);
			}
			properties.setProperty(key, value);
		}
		return properties;
	}

	private Properties sortProperties(Properties properties) throws ConfigurationException, IOException {
		Properties sp = new SortedProperties();
		sp.putAll(properties);

		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		sp.store(baos, null);

		properties.clear();
		properties.load(new ByteArrayInputStream(baos.toByteArray()));

		return properties;
	}

    protected boolean isAWildCard(String key) {
		String regexVariable = "bw\\[[^\\**]*\\]/variables\\[.*\\]/variable\\[.*\\]"; // is a wildcard only if it has a '*' in bw[] for variables (because a variable can have '*' in their name)

		return key.contains("*") && !Pattern.matches(regexVariable, key);
    }

    /**
     *

     * This expands wild cards properties.

     * Both wildcard expressions and expressions to expand are present in the
     * same properties object.

     * Example
     *

     *
property with wildcard: /root/element[*]/key=new_value

     *
property matching: /root/element[my_name]/key=old_value

     *

     *  will expand to:

     *

     *
property after expansion:
     * /root/element[my_name]/key=new_value

     *

     *

     *
     * @param properties, the properties object with wildcard expressions and
     * expressions to expand
     * @return properties with expanded expressions, but without wildcard
     * expressions
     */
    protected Properties expandWildCards(Properties properties) {
    	Properties propertiesWithWildCards = new Properties() { // sorted properties
			private static final long serialVersionUID = 7793482336210629858L;

			@Override
		    public synchronized Enumeration<Object> keys() {
		        return Collections.enumeration(new TreeSet<Object>(super.keySet()));
		    }
		};
    	String key;

    	// retrieve the keys with WildCards
		Enumeration<Object> e = properties.keys();
   		while (e.hasMoreElements()) {
    		key = (String) e.nextElement();
    		if (isAWildCard(key)) {
    			propertiesWithWildCards.setProperty(key, properties.getProperty(key));
    			properties.remove(key);
    		}
    	}

    	// try to replace the values of other keys matching the keys with WildCards
		Enumeration<Object> w = propertiesWithWildCards.keys();
   		while (w.hasMoreElements()) {
    		String keyWithWildCards = (String) w.nextElement();
    		String regex = wildcardToRegex(keyWithWildCards);

			String ignoreWildcardInVariablesPattern = "(.*)variables\\\\\\[(.*)\\\\\\]\\/variable\\\\\\[(.*)\\\\\\](.*)";
			Pattern p = Pattern.compile(ignoreWildcardInVariablesPattern);
			Matcher m = p.matcher(regex);
			if (m.matches()) {
				String variables = m.group(2);
				String variable = m.group(3);
				variables = variables.replace(".*", "\\*");
				variable = variable.replace(".*", "\\*");
				regex = m.group(1) + "variables\\[" + variables + "\\]/variable\\[" + variable + "\\]" + m.group(4);
			}

    		Boolean found = false;

    		e = properties.keys();
    	   	while (e.hasMoreElements()) {
    			key = (String) e.nextElement();

    			if (Pattern.matches(regex, key)) {
    				found = true;
    				String value = (String) propertiesWithWildCards.getProperty(keyWithWildCards);
    				properties.setProperty(key, value);
    			}
    		}

    	   	// not found, we put back the expression with wild cards in the original list (false positive)
    	   	// this way the wildcard can still be used in a next pass and will be removed at the end by AbstractPackagingMojo.removeWildCards
    		if (!found) {
    			properties.setProperty(keyWithWildCards, propertiesWithWildCards.getProperty(keyWithWildCards));
    		}
    	}

    	return properties;
    }

    protected Properties removeWildCards(Properties properties) {
    	String key;

		Enumeration<Object> e = properties.keys();
    	while (e.hasMoreElements()) {
    		key = (String) e.nextElement();

    		if (isAWildCard(key)) {
    			properties.remove(key);
    		}
    	}

    	return properties;
    }

	public void execute() throws MojoExecutionException {
		if (super.skip()) {
			return;
		}

		if (ignorePropertiesMerge) return; // ignore all properties merging

		getLog().info(MERGING_PROPERTIES);
		try {
			Properties earGlobalVariables = loadPropertiesFile(deploymentGlobalVariables);
			Properties earServices = loadPropertiesFile(deploymentServices);

			MergedFiles mergedCommonFiles = MergedFiles.NONE, mergedReferenceFiles = MergedFiles.NONE;

			if (mergeCommonLast) {
				if (!ignoreReferenceFiles) {
					mergedReferenceFiles = mergeFiles(earGlobalVariables,
													  earServices,
													  deploymentGlobalVariablesReference,
													  deploymentServicesReference,
													  USING_GVS_REFERENCE_FILE,
													  USING_SERVICES_REFERENCE_FILE);
				}
				if (!ignoreCommonFiles) {
					mergedCommonFiles = mergeFiles(earGlobalVariables,
							   					   earServices,
							   					   deploymentGlobalVariablesCommon,
							   					   deploymentServicesCommon,
							   					   USING_GVS_COMMON_FILE,
							   					   USING_SERVICES_COMMON_FILE);
				}
			} else {
				if (!ignoreCommonFiles) {
					mergedCommonFiles = mergeFiles(earGlobalVariables,
												   earServices,
												   deploymentGlobalVariablesCommon,
												   deploymentServicesCommon,
												   USING_GVS_COMMON_FILE,
												   USING_SERVICES_COMMON_FILE);
				}
				if (!ignoreReferenceFiles) {
					mergedReferenceFiles = mergeFiles(earGlobalVariables,
							  						  earServices,
							  						  deploymentGlobalVariablesReference,
							  						  deploymentServicesReference,
							  						  USING_GVS_REFERENCE_FILE,
							  						  USING_SERVICES_REFERENCE_FILE);
				}
			}

		    earGlobalVariables = sortProperties(earGlobalVariables);
		    earServices = sortProperties(earServices);

		    earServices = removeWildCards(earServices);
		    if (!alwaysKeepEmptyBindings) {
		    	earServices = removeEmptyBindings(earServices);
		    }

			if (mergedCommonFiles == MergedFiles.GV ||
			    mergedCommonFiles == MergedFiles.BOTH ||
			    mergedReferenceFiles == MergedFiles.GV ||
			    mergedReferenceFiles == MergedFiles.BOTH ||
			    mergedCommonFiles == MergedFiles.SERVICES ||
			    mergedCommonFiles == MergedFiles.BOTH ||
			    mergedReferenceFiles == MergedFiles.SERVICES ||
			    mergedReferenceFiles == MergedFiles.BOTH) {

				getLog().info("");
			} else {
				getLog().debug("GV ref: " + deploymentGlobalVariablesReference.getAbsolutePath());
				getLog().debug("SVC ref: " + deploymentServicesReference.getAbsolutePath());
				getLog().debug("GV common: " + deploymentGlobalVariablesCommon.getAbsolutePath());
				getLog().debug("SVC common: " + deploymentServicesCommon.getAbsolutePath());
				getLog().info(NOTHING_TO_MERGE);
			}

			// Export Properties in a properties file
			//  Global Variables
			if (mergedCommonFiles == MergedFiles.GV ||
			    mergedCommonFiles == MergedFiles.BOTH ||
			    mergedReferenceFiles == MergedFiles.GV ||
			    mergedReferenceFiles == MergedFiles.BOTH) {
				savePropertiesToFile(deploymentGlobalVariables,
									 earGlobalVariables,
									 "Global Variables",
									 PROPERTIES_SAVE_GVS_SUCCESS,
									 PROPERTIES_SAVE_GVS_FAILURE);
			}
			//  Services (=~ Process Archives)
			if (mergedCommonFiles == MergedFiles.SERVICES ||
			    mergedCommonFiles == MergedFiles.BOTH ||
			    mergedReferenceFiles == MergedFiles.SERVICES ||
			    mergedReferenceFiles == MergedFiles.BOTH) {
				savePropertiesToFile(deploymentServices,
									 earServices,
									 "Services (Bindings, Processes)",
									 PROPERTIES_SAVE_SERVICES_SUCCESS,
									 PROPERTIES_SAVE_SERVICES_FAILURE);
			}
		} catch (Exception e) {
			throw new MojoExecutionException(MERGE_FAILURE, e);
		}
	}

	private Properties removeEmptyBindings(Properties properties) {
		ArrayList<String> pars = new ArrayList<String>();

		Pattern pNotEmptyBinding = Pattern.compile(regexNotEmptyBinding);
		Pattern pEmptyBinding = Pattern.compile(regexEmptyBinding);
		String parName;

		Enumeration<Object> e = properties.keys();
		// first check if there is at least one non empty binding (non default)
	   	while (e.hasMoreElements()) {
			String key = (String) e.nextElement();
			Matcher mNotEmptyBinding = pNotEmptyBinding.matcher(key);
			if (mNotEmptyBinding.matches()) {
				parName = mNotEmptyBinding.group(1);
				if (pars.contains(parName)) continue;
				pars.add(parName);
			}
		}
	   	// then delete
		e = properties.keys();
	   	while (e.hasMoreElements()) {
	   		String key = (String) e.nextElement();
	   		Matcher mEmptyBinding = pEmptyBinding.matcher(key);
	   		if (mEmptyBinding.matches()) {
	   			parName = mEmptyBinding.group(1);
	   			if (pars.contains(parName)) {
	   				properties.remove(key);
	   			}
	   		}
	   	}

		return properties;
	}

}