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

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;
import org.jboss.netty.bootstrap.ConnectionlessBootstrap;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipeline;

public class ServerManager {

    private final List<TrackerServer> serverList = new LinkedList<TrackerServer>();

    public void init() throws Exception {

        ClassLoader cl = ServerManager.class.getClassLoader();
        String pack = "org/traccar/protocol";
        String dottedPackage = pack.replaceAll("[/]", ".");

        BufferedReader reader = new BufferedReader(new InputStreamReader(cl.getResourceAsStream(pack)));
        String line = null;
        while ((line = reader.readLine()) != null) {
            if (line.endsWith(".class")) {
                Class protocolClass = Class.forName(dottedPackage + "." + line.substring(0, line.lastIndexOf('.')));
                if (BaseProtocol.class.isAssignableFrom(protocolClass)) {
                    initProtocolServer((BaseProtocol) protocolClass.newInstance());
                }
            }
        }

        initProtocolDetector();
    }

    public void start() {
        for (Object server: serverList) {
            ((TrackerServer) server).start();
        }
    }

    public void stop() {
        for (Object server: serverList) {
            ((TrackerServer) server).stop();
        }

        // Release resources
        GlobalChannelFactory.release();
        GlobalTimer.release();
    }

    private boolean isProtocolEnabled(String protocol) {
        return Context.getProps().containsKey(protocol + ".port");
    }

    private void initProtocolDetector() throws SQLException {
        String protocol = "detector";
        if (isProtocolEnabled(protocol)) {
            serverList.add(new TrackerServer(new ServerBootstrap(), protocol) {
                @Override
                protected void addSpecificHandlers(ChannelPipeline pipeline) {
                    pipeline.addLast("detectorHandler", new DetectorHandler(serverList));
                }
            });
            serverList.add(new TrackerServer(new ConnectionlessBootstrap(), protocol) {
                @Override
                protected void addSpecificHandlers(ChannelPipeline pipeline) {
                    pipeline.addLast("detectorHandler", new DetectorHandler(serverList));
                }
            });
        }
    }

    private void initProtocolServer(final Protocol protocol) throws SQLException {
        if (isProtocolEnabled(protocol.getName())) {
            protocol.initTrackerServers(serverList);
        }
    }

}

@@ -666,53 +666,79 @@
 .io.
-BufferedReader;%0Aimport java.io.InputStreamRea
+File;%0Aimport java.net.URI;%0Aimport java.net.URL;%0Aimport java.net.URLDeco
 der;
@@ -768,16 +768,46 @@
 eption;%0A
+import java.util.Enumeration;%0A
 import j
@@ -846,24 +846,85 @@
 .util.List;%0A
+import java.util.jar.JarEntry;%0Aimport java.util.jar.JarFile;%0A
 import org.j
@@ -1238,59 +1238,51 @@
     
-ClassLoader cl = ServerManager.class.getClassLoader
+List%3CString%3E names = new LinkedList%3CString%3E
 ();%0A
@@ -1304,24 +1304,31 @@
 pack
+ageName
  = %22org
-/
+.
 traccar
-/
+.
 prot
@@ -1353,36 +1353,41 @@
 ing 
-dottedP
+p
 ackage
+Path
  = pack
+ageName
 .replace
 All(
@@ -1386,34 +1386,28 @@
 lace
-All(%22%5B/%5D%22, %22.%22
+('.', '/'
 );%0A
-%0A
         
 Buff
@@ -1406,131 +1406,398 @@
     
-BufferedReader reader = new BufferedReader(new InputStreamReader(cl.getResourceAsStream(pack)));%0A        String line = null
+URL packageUrl = Thread.currentThread().getContextClassLoader().getResource(packagePath);%0A%0A        if (packageUrl.getProtocol().equals(%22jar%22)) %7B%0A            String jarFileName = URLDecoder.decode(packageUrl.getFile(), %22UTF-8%22);%0A            JarFile jf = new JarFile(jarFileName.substring(5, jarFileName.indexOf(%22!%22)));%0A            %0A            Enumeration%3CJarEntry%3E jarEntries = jf.entries()
 ;%0A  
@@ -1806,95 +1806,349 @@
     
+ 
+   
 while
- ((line = reader.readLine()) != null) %7B%0A            if (line.endsWith(%22.class%22)) %7B
+(jarEntries.hasMoreElements())%7B%0A                String entryName = jarEntries.nextElement().getName();%0A                if (entryName.startsWith(packagePath) && entryName.length() %3E packagePath.length() + 5) %7B%0A                    names.add(entryName.substring(packagePath.length() + 1, entryName.lastIndexOf('.')));%0A                %7D
 %0A   
@@ -2160,73 +2160,268 @@
     
+%7D%0A
     
-Class protocolClass = Class.forName(dottedPackage + %22.%22 + lin
+    %7D else %7B%0A            File folder = new File(new URI(packageUrl.toString()));%0A            File%5B%5D files = folder.listFiles();%0A            for (File actual: files) %7B%0A                String entryName = actual.getName();%0A                names.add(entryNam
 e.su
@@ -2431,19 +2431,24 @@
 ring(0, 
-lin
+entryNam
 e.lastIn
@@ -2457,32 +2457,172 @@
 xOf('.')));%0A    
+        %7D%0A        %7D%0A        %0A        for (String name : names) %7B%0A            Class protocolClass = Class.forName(packageName + '.' + name);%0A
             if (
@@ -2671,28 +2671,24 @@
 olClass)) %7B%0A
-    
             
@@ -2755,34 +2755,16 @@
 nce());%0A
-                %7D%0A
         

Fix dynamic class loading (fix #1283)