package com.dbxml.db.server;

/*
 * dbXML - Native XML Database
 * Copyright (C) 1999-2004  The dbXML Group, L.L.C.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Id: ServiceManager.java,v 1.2 2004/02/12 00:17:57 bradford Exp $
 */

import com.dbxml.db.core.ClassResolver;
import com.dbxml.util.Configurable;
import com.dbxml.util.Configuration;
import com.dbxml.util.ConfigurationCallback;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
 * ServiceManager
 */

public final class ServiceManager implements Configurable {
   private static final String[] EmptyStrings = new String[0];
   private static final Service[] EmptyServices = new Service[0];

   private static final String SERVICE = "service";
   private static final String CLASS = "class";

   private Server server;
   private Configuration config;
   private List services = Collections.synchronizedList(new ArrayList()); // of Service
   private Map svcMap = Collections.synchronizedMap(new TreeMap());

   public void setServer(Server server) {
      this.server = server;
   }

   public void setConfig(Configuration config) {
      this.config = config;
      config.processChildren(SERVICE,
         new ConfigurationCallback() {
            public void process(Configuration cfg) {
               String className = cfg.getAttribute(CLASS);
               try {
                  Object obj = ClassResolver.get(className).newInstance();
                  if ( obj instanceof Service ) {
                     Service service = (Service)obj;
                     service.setServerInstance(server);

                     if ( obj instanceof Configurable )
                        ((Configurable)obj).setConfig(cfg);

                     addService(service);
                  }
                  else
                     System.err.println("ERROR: '" + className + "' is not a service");
               }
               catch ( Exception e ) {
                  System.err.println("FATAL ERROR: Loading service '" + className + "'" + e);
                  e.printStackTrace(System.err);
                  System.exit(1);
               }
            }
         });
   }

   public Configuration getConfig() {
      return config;
   }

   public boolean startServices() {
      boolean ok = true;
      Service[] svc = (Service[])services.toArray(EmptyServices);
      for ( int i = 0; i < svc.length; i++ ) {
         String name = svc[i].getName();
         if ( svc[i].start() == Service.RESULT_OK )
            System.out.println("Service: '" + name + "' " + svc[i].statusMessage());
         else {
            System.err.println("ERROR: Could not start service '" + name + "'");
            ok = false;
         }
      }
      return ok;
   }

   public void stopServices() {
      Service[] svc = (Service[])services.toArray(EmptyServices);
      for ( int i = svc.length - 1; i >= 0; i-- ) {
         String name = svc[i].getName();
         if ( svc[i].stop() == Service.RESULT_OK )
            System.out.println("Service: '" + name + "' stopped");
         else
            System.err.println("ERROR: Could not stop service '" + name + "'");
      }
   }

   public boolean addService(Service service) {
      String name = service.getName();
      if ( getService(name) != null ) {
         System.err.println("ERROR: Could not add service '" + name + "'");
         System.err.println("The service name duplicates one already in the service manager");
         return false;
      }
      if ( service.initialize() == Service.RESULT_OK ) {
         services.add(service);
         svcMap.put(name, service);
      }
      else {
         System.err.println("ERROR: Could not initialize service '" + name + "'");
         return false;
      }
      return true;
   }

   public boolean removeService(Service service) {
      if ( service.status() == Service.STATE_STARTED )
         service.stop();
      service.uninitialize();
      services.remove(service);
      svcMap.remove(service.getName());
      service.dispose();
      return true;
   }

   public String[] listServices() {
      return (String[])svcMap.keySet().toArray(EmptyStrings);
   }

   public Service getService(String name) {
      return (Service)svcMap.get(name);
   }

   public void dispose() {
      Service[] svc = (Service[])services.toArray(EmptyServices);
      for ( int i = svc.length - 1; i >= 0; i-- ) {
         svc[i].uninitialize();
         svc[i].dispose();
      }
   }
}
