/*
 * The contents of this file are subject to the terms 
 * of the Common Development and Distribution License 
 * (the License).  You may not use this file except in
 * compliance with the License.
 * 
 * You can obtain a copy of the license at 
 * https://glassfish.dev.java.net/public/CDDLv1.0.html or
 * glassfish/bootstrap/legal/CDDLv1.0.txt.
 * See the License for the specific language governing 
 * permissions and limitations under the License.
 * 
 * When distributing Covered Code, include this CDDL 
 * Header Notice in each file and include the License file 
 * at glassfish/bootstrap/legal/CDDLv1.0.txt.  
 * If applicable, add the following below the CDDL Header, 
 * with the fields enclosed by brackets [] replaced by
 * you own identifying information: 
 * "Portions Copyrighted [year] [name of copyright owner]"
 * 
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 */
package com.sun.enterprise.jbi.serviceengine.bridge;

import com.sun.enterprise.deployment.WebServiceEndpoint;
import com.sun.enterprise.jbi.serviceengine.ServiceEngineException;
import com.sun.enterprise.jbi.serviceengine.core.ServiceEngineEndpoint;
import com.sun.enterprise.jbi.serviceengine.core.EndpointRegistry;
import com.sun.enterprise.jbi.serviceengine.core.JavaEEServiceEngineContext;
import com.sun.enterprise.webservice.monitoring.WebServiceEngine;
import com.sun.enterprise.webservice.monitoring.Endpoint;
import com.sun.enterprise.webservice.monitoring.EndpointLifecycleListener;
import com.sun.enterprise.webservice.monitoring.WebServiceEngineFactory;
import com.sun.enterprise.config.serverbeans.*;
import com.sun.enterprise.config.ConfigBean;
import com.sun.enterprise.config.ConfigContext;
import com.sun.enterprise.deployment.Application;
import com.sun.enterprise.server.*;
import com.sun.logging.LogDomains;
import javax.jbi.component.ComponentContext;
import java.util.Map;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.Iterator;
import java.util.logging.Logger;
import javax.jbi.servicedesc.ServiceEndpoint;
import javax.xml.namespace.QName;

/**
 * A utillity class which keeps track of JBI enabled end points
 * @author Manisha Umbarje
 */
public class EndpointHelper {
    
    /** A web service engine */
    private WebServiceEngine engine ;
    private ComponentContext context ;
    private EndpointRegistry registry;
    private Map uriToDetailsMap ;
    private static EndpointHelper helper;
    private EndpointLifecycleListener epLifecycleListener;
    /**
     * Internal handle to the logger instance
     */
    protected static final Logger logger =
            LogDomains.getLogger(LogDomains.SERVER_LOGGER);
    
    /** Creates a new instance of EndpointHelper */
    private EndpointHelper() {
        engine = WebServiceEngineFactory.getInstance().getEngine();
        epLifecycleListener = new EndpointLifecycleListenerImpl();
        engine.addLifecycleListener(epLifecycleListener);
        context = JavaEEServiceEngineContext.getInstance().getJBIContext();
        registry = EndpointRegistry.getInstance();
        uriToDetailsMap = new HashMap();
    }
    
    public static EndpointHelper getInstance() {
        if (helper == null) {
            helper = new EndpointHelper();
        }
        return helper;
    }
    
    public void initialize() {
        Iterator<Endpoint> endpoints = engine.getEndpoints();
        while(endpoints.hasNext()) {
            registerEndpoint(endpoints.next());
        }
    }
    
    public void enableEndpoint(QName service, String endpointName) {
        if(endpointName != null) {
            ServiceEngineEndpoint endpoint = registry.get(service, endpointName);
            if(endpoint != null && (!endpoint.isEnabled())) {
                try {
                    ServiceEndpoint jbiEndpoint = context.activateEndpoint(
                            endpoint.getServiceName(),
                            endpoint.getEndpointName());
                    endpoint.setServiceEndpoint(jbiEndpoint);
                    endpoint.setEnabled(true);
                    debug(Level.INFO,"serviceengine.enable_endpoint",
                            new Object[]{service.getLocalPart(), endpointName});
                } catch(Exception e) {
                    debug(Level.INFO,"serviceengine.error_enable",
                            new Object[]{service.getLocalPart(), endpointName});
                            
                }
            }
        }
    }

    /**
     * Activates the end point in JBI
     * @param endPoint endPoint to be activated in JBI
     */
    public void registerEndpoint(Endpoint endpoint) {
        registerEndpoint(endpoint.getDescriptor());
    }
    
    public void registerEndpoint(WebServiceEndpoint webServiceDesc) {
        if(webServiceDesc != null) {
            // activate the end point in JBI
            String endpointName = webServiceDesc.hasWsdlPort() ? webServiceDesc.getWsdlPort().getLocalPart() : webServiceDesc.getEndpointName();
         
            debug(Level.FINE,"serviceengine.start_registration",
                    new Object[]{webServiceDesc.getServiceName(),
                            endpointName});
                
            try {
           
                boolean ejbType = webServiceDesc.implementedByEjbComponent() ;
                boolean jaxwsFlag = 
                        webServiceDesc.getWebService().getMappingFileUri() == null;
                String relativeURI = webServiceDesc.getEndpointAddressUri();
                ClassLoader classLoader = webServiceDesc.getBundleDescriptor().getClassLoader();
                //logger.info(" ClassLoader in service engine is : "+ classLoader);
                String implClass = null;
                String contextRoot = null;
                ServiceEndpoint endpoint = null;
                ServiceEngineEndpoint seEndpoint = null;
                if(ejbType) {
                    implClass = webServiceDesc.getTieClassName();
                } else {
                    implClass = webServiceDesc.getServletImplClass();
                    contextRoot =
                            webServiceDesc.getWebComponentImpl().
                            getWebBundleDescriptor().getContextRoot();
                    relativeURI = contextRoot + relativeURI;
                }
                if(isJBIEnabled(webServiceDesc))  {
                    endpoint = context.activateEndpoint(
                            webServiceDesc.getServiceName(),
                            endpointName);
                    seEndpoint = new ServiceEngineEndpoint(endpoint,
                        webServiceDesc.getWebService().getGeneratedWsdlFilePath(),
                        webServiceDesc.getServiceEndpointInterface(),
                        implClass, webServiceDesc.getEndpointAddressUri(),
                        contextRoot,ejbType, 
                        jaxwsFlag, true, classLoader);
                     debug(Level.INFO,"serviceengine.success_registration",
                             new Object[]{webServiceDesc.getServiceName(),
                            endpointName});

                } else {
                    seEndpoint = new ServiceEngineEndpoint(webServiceDesc.getServiceName(),
                        endpointName,    
                        webServiceDesc.getWebService().getGeneratedWsdlFilePath(),
                        webServiceDesc.getServiceEndpointInterface(),
                        implClass, webServiceDesc.getEndpointAddressUri(),
                        contextRoot,ejbType, 
                        jaxwsFlag, true, classLoader);
                    seEndpoint.setEnabled(false);
                }
                    
                // even if jbi-enabled flag is off, internal registries keep track 
                // of deployed web services in SJSAS 
                registry.put(webServiceDesc.getServiceName(),
                        endpointName, seEndpoint);
                
                uriToDetailsMap.put(relativeURI,
                        new Object[]{webServiceDesc.getServiceName(),
                                endpointName});
            } catch (Exception e) {
                debug(Level.INFO,"serviceengine.error_registration",
                        new Object[]{webServiceDesc.getServiceName(),
                                endpointName});
                
            }
                            
        }
    }
    
    /**
     * Deactivates the end point in JBI
     * @param endPoint endPoint to be deactivated in JBI
     */
    public void disableEndpoint(QName service, String endpointName) {
        // deactivates the end point in JBI
        ServiceEngineEndpoint endpoint = registry.get(service, endpointName);
        
        if (endpoint != null) {
            try {
                ServiceEndpoint endpt = endpoint.getServiceEndpoint();
                // It's assumed that ServiceEndpoint is priorly activated in JBI
                if(endpt != null ) {
                    context.deactivateEndpoint(endpt);
                    endpoint.setEnabled(false);
                    debug(Level.INFO,"serviceengine.disable_endpoint",
                            new Object[]{service.getLocalPart(), endpointName});
                }
            } catch(Exception e) {
                debug(Level.INFO,"serviceengine.error_disable",
                        new Object[]{service.getLocalPart(), endpointName});
                        
            }
        }
    }
    
    public void unregisterEndpoint(QName service, String endpointName) {
        if(endpointName != null) {
            ServiceEngineEndpoint endpoint = registry.get(service, endpointName);
            
            if(endpoint != null) {
                String endpointURI = endpoint.getURI();
                disableEndpoint(service, endpointName);
                registry.delete(service, endpointName);
                RuntimeEndpointInfoRegistryImpl.getInstance().
                        deleteRuntimeEndpointInfo(service,endpointName);
                uriToDetailsMap.remove(endpointURI);
                debug(Level.INFO,"serviceengine.success_removal",
                        new Object[]{service.getLocalPart(), endpointName});
            }
        }
    }
    
    public void toggleEndpointStatus(String uri, boolean flag) {
        Object[] endpointInfo = (Object[])uriToDetailsMap.get(uri);
        if(endpointInfo != null) {
            if(flag)
                enableEndpoint((QName)endpointInfo[0], (String)endpointInfo[1]);
            else
                disableEndpoint((QName)endpointInfo[0], (String)endpointInfo[1]);
        }
        
    }
    
    public void destroy() {
        engine.removeLifecycleListener(epLifecycleListener);
    }
    
    private void debug(Level logLevel, String msgID, Object[] params) {
        logger.log(logLevel, msgID, params);
    }
    
    private boolean isJBIEnabled(WebServiceEndpoint endpoint) {
        try {
            String applicationName =
                    endpoint.getWebService().getBundleDescriptor().getApplication().getRegistrationName();
            ConfigContext configContext =
                    ApplicationServer.getServerContext().getConfigContext();
            ConfigBean app =
                    ApplicationHelper.findApplication(configContext,applicationName);
            String type =
                    ApplicationHelper.getApplicationType(configContext,
                    applicationName);
            String endpointName = endpoint.getEndpointName();
            if(type.equals(Applications.J2EE_APPLICATION)) {
                com.sun.enterprise.config.serverbeans.WebServiceEndpoint endpointBean =
                        ((J2eeApplication)app).getWebServiceEndpointByName(endpointName);
                if(endpointBean  != null)
                    return endpointBean.isJbiEnabled();
            } else if (type.equals(Applications.EJB_MODULE)) {
                com.sun.enterprise.config.serverbeans.WebServiceEndpoint endpointBean =
                        ((EjbModule)app).getWebServiceEndpointByName(endpointName);
                if(endpointBean  != null)
                    return endpointBean.isJbiEnabled();
            } else if (type.equals(Applications.WEB_MODULE)) {
                com.sun.enterprise.config.serverbeans.WebServiceEndpoint endpointBean =
                        ((WebModule)app).getWebServiceEndpointByName(endpointName);
                if(endpointBean  != null)
                    return endpointBean.isJbiEnabled();
            }
        } catch(Throwable ce) {
            debug(Level.INFO,"serviceengine.config_not_found",
                    new Object[]{endpoint.getServiceName(),
                            endpoint.getEndpointName()});
        }
        // By default endpoints are enabled
        return true;
    }
    
}
