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

package org.wso2.carbon.mss.internal.deployer;

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

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

/**
 * Dynamically initialising a set of objects from a given jar
 * according to the manifest entry 'microservices'
 */
public class MSSJarProcessor {
    private static final Logger log = LoggerFactory.getLogger(MSSJarProcessor.class);
    private static final String MICROSERVICES_MANIFEST_KEY = "microservices";
    private File file;
    private List<Object> resourceInstances = new ArrayList<>();

    /**
     * @param file jar file to be processed
     */
    public MSSJarProcessor setArtifact(File file) {
        this.file = file;
        return this;
    }

    /**
     * Initialize a list of objects from the jar for the specified
     * classes in the jar's manifest file under 'microservices' key
     */
    public MSSJarProcessor process() {
        String jarPath = file.getAbsolutePath();
        String[] mssClassNames = readMSSManifestEntry(jarPath);
        URLClassLoader classLoader;
        try {
            //parent class loader is required to provide classes that are outside of the jar
            classLoader = new URLClassLoader(new URL[]{file.toURI().toURL()}, this.getClass().getClassLoader());
        } catch (MalformedURLException e) {
            log.error("Path to jar is invalid");
            return this;
        }
        for (String className : mssClassNames) {
            try {
                Class classToLoad = classLoader.loadClass(className);
                resourceInstances.add(classToLoad.newInstance());
                log.info("initialized class: " + className);
            } catch (ClassNotFoundException e) {
                log.error("Class: " + className + " not found");
            } catch (InstantiationException e1) {
                log.error("Failed to initialize class: " + className);
            } catch (IllegalAccessException e1) {
                log.error("Failed to access class: " + className);
            }
        }
        return this;
    }

    /**
     * Extracts the comma separated list of fully qualified class
     * names of the 'microservices' key of the jar's maifest file
     *
     * @param jarPath absolute path to the jar file
     * @return String array of fully qualified class names
     */
    private String[] readMSSManifestEntry(String jarPath) {
        JarFile jarFile;
        try {
            jarFile = new JarFile(jarPath);
        } catch (IOException e) {
            log.error("Error loading artifact jar: " + jarPath);
            return new String[0];
        }
        Manifest manifest;
        try {
            manifest = jarFile.getManifest();
        } catch (IOException e) {
            log.error("Error retrieving manifest: " + jarPath);
            return new String[0];
        }
        Attributes mainAttributes = manifest.getMainAttributes();
        String mssEntry = mainAttributes.getValue(MICROSERVICES_MANIFEST_KEY);
        if (mssEntry == null) {
            log.error("\'microservices\' manifest entry not found: " + jarPath);
            return new String[0];
        }
        return mssEntry.split("\\s*,\\s*");
    }

    /**
     * Return the initialized objects
     *
     * @return List of initialized objects
     */
    public List<Object> getResourceInstances() {
        return resourceInstances;
    }
}

@@ -1961,17 +1961,17 @@
       //
-p
+P
 arent cl
@@ -2040,16 +2040,120 @@
 the jar%0A
+            //A Privileged Block is not required to initialise class loader since this code is internal%0A
         
@@ -3402,16 +3402,23 @@
  jarFile
+ = null
 ;%0A      
@@ -3481,195 +3481,20 @@
     
-%7D catch (IOException e) %7B%0A            log.error(%22Error loading artifact jar: %22 + jarPath);%0A            return new String%5B0%5D;%0A        %7D%0A        Manifest manifest;%0A        try %7B%0A           
+    Manifest
  man
@@ -3536,34 +3536,40 @@
     
-%7D catch (IOException e) %7B%0A
+    if (manifest == null) %7B%0A    
     
@@ -3632,32 +3632,36 @@
 h);%0A            
+ 
+   
 return new Strin
@@ -3674,26 +3674,33 @@
         
-%7D%0A
+    %7D%0A   
         
 Attribut
@@ -3691,16 +3691,17 @@
         
+ 
 Attribut
@@ -3746,24 +3746,28 @@
 tributes();%0A
+    
         Stri
@@ -3833,16 +3833,20 @@
 T_KEY);%0A
+    
         
@@ -3873,32 +3873,36 @@
 ) %7B%0A            
+    
 log.error(%22%5C'mic
@@ -3958,32 +3958,36 @@
 h);%0A            
+    
 return new Strin
@@ -3992,34 +3992,42 @@
 ing%5B0%5D;%0A        
+  
-%7D%0A
+  %7D%0A    
         return m
@@ -4050,24 +4050,395 @@
 %5Cs*,%5C%5Cs*%22);%0A
+        %7D catch (IOException e) %7B%0A            log.error(%22Error retrieving manifest: %22 + jarPath);%0A            return new String%5B0%5D;%0A        %7D finally %7B%0A            if (jarFile != null) %7B%0A                try %7B%0A                    jarFile.close();%0A                %7D catch (IOException e) %7B%0A                    e.printStackTrace();%0A                %7D%0A            %7D%0A        %7D%0A
     %7D%0A%0A    /

Fix findbugs issues