geronimo-scm mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jboy...@apache.org
Subject cvs commit: incubator-geronimo/modules/core/src/java/org/apache/geronimo/console/cli DConfigBeanConfigurator.java Deployer.java
Date Thu, 04 Sep 2003 05:26:19 GMT
jboynes     2003/09/03 22:26:19

  Added:       modules/core/src/java/org/apache/geronimo/console/cli
                        DConfigBeanConfigurator.java Deployer.java
  Log:
  GERONIMO-10 patch (v5)  from Aaron Mulder
  Not sure on these and their relationship to twiddle - is this duplicate functionality?
  
  Revision  Changes    Path
  1.1                  incubator-geronimo/modules/core/src/java/org/apache/geronimo/console/cli/DConfigBeanConfigurator.java
  
  Index: DConfigBeanConfigurator.java
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2003 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache Geronimo" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache Geronimo", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * ====================================================================
   */
  package org.apache.geronimo.console.cli;
  
  import java.beans.*;
  import java.io.*;
  import java.util.*;
  import java.lang.reflect.InvocationTargetException;
  import javax.enterprise.deploy.spi.DConfigBean;
  import javax.enterprise.deploy.spi.DConfigBeanRoot;
  import javax.enterprise.deploy.spi.exceptions.ConfigurationException;
  import javax.enterprise.deploy.model.DDBean;
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  import org.apache.geronimo.common.propertyeditor.PropertyEditors;
  
  /**
   * Knows how to configure a DConfigBean at the command line.  The editing process
   * is a series of reads and writes to the provided input and output streams,
   * which basically presents information and a prompt to the user, gathers their
   * input, and repeats.  They can navigate through a tree of DConfigBeans and
   * Java Beans, adding, removing, and editing properies on beans where
   * appropriate.
   * <p>
   * Note: it might make sense to break this class up eventually.  Particularly if
   * we want to allow the user to navigate between arbitrary DDBeans (standard DD)
   * and their matching DConfigBeans (server-specific DD).  Right now they can only
   * edit one tree at a time, either the whole DDBean tree, or the whole
   * DConfigBean tree.
   * </p>
   * @version $Revision: 1.1 $ $Date: 2003/09/04 05:26:19 $
   */
  public class DConfigBeanConfigurator {
      private final static Log log = LogFactory.getLog(DConfigBeanConfigurator.class);
      private PrintWriter out;
      private BufferedReader in;
      private Stack beans = new Stack();
  
      /**
       * Creates a new instance, based on the supplied config bean root and
       * input and output streams.
       */
      public DConfigBeanConfigurator(DConfigBeanRoot bean, PrintWriter out, BufferedReader
in) {
          this.out = out;
          this.in = in;
          beans.push(bean);
      }
  
      /**
       * Begins the process of configuring the DConfigBean tree.  When this method
       * returns, the user has finished editing the DConfigBeans (or a fatal error
       * caused the editing to abort).
       *
       * @return <code>true</code> if the editing completed normally
       *        (<code>false</code> if there was a fatal error).
       */
      public boolean configure() {
          try {
              initialize();
              return true;
          } catch(IntrospectionException e) {
              log.error("Unable to introspect a JavaBean", e);
          } catch(IOException e) {
              log.error("Unable to gather input from user", e);
          } catch(InvocationTargetException e) {
              log.error("Unable to read or write a JavaBean property", e.getTargetException());
          } catch(IllegalAccessException e) {
              log.error("Unable to read or write a JavaBean property", e);
          } catch(ConfigurationException e) {
              log.error("Unable to generate a child DConfigBean", e);
          } catch(InstantiationException e) {
              log.error("Unable to generate a child bean", e);
          }
          return false;
      }
  
      /**
       * The main logic loop for the editing process.  This starts an endless loop,
       * where each iteration prints information on the current bean and prompts
       * the user for an action.  A stack is maintained of the current beans from
       * root (bottom of the stack) to the current leaf node (top of the stack).
       * The main options offered here are to move to a parent or child bean (if
       * available) or to edit a property on the current bean.
       */
      private void initialize() throws IntrospectionException, IOException, InvocationTargetException,
IllegalAccessException, ConfigurationException, InstantiationException {
          boolean forward = true;
          BeanInfo info;
          PropertyDescriptor[] properties = new PropertyDescriptor[0];
          PropertyDescriptor[] readOnly = new PropertyDescriptor[0];
          PropertyDescriptor[] childProps = new PropertyDescriptor[0];
          Map childTypes = new HashMap();
          while(true) {
              out.println("\n\n");
              Object bean = beans.peek();
              int count;
  
              // Load top-level info
              info = Introspector.getBeanInfo(bean.getClass());
              String indent = printLocation();
  
              // Load children
              childTypes.clear();
              if(bean instanceof DConfigBean) {
                  DConfigBean dcb = (DConfigBean) bean;
                  String[] xpaths = dcb.getXpaths();
                  for(int i=0; i<xpaths.length; i++) {
                      DDBean[] ddbs = dcb.getDDBean().getChildBean(xpaths[i]);
                      if(ddbs.length != 0) {
                          DConfigBean[] list = new DConfigBean[ddbs.length];
                          for(int j = 0; j < ddbs.length; j++) {
                              list[j] = dcb.getDConfigBean(ddbs[j]);
                          }
                          childTypes.put(Introspector.getBeanInfo(list[0].getClass()).getBeanDescriptor().getDisplayName(),
list);
                      }
                  }
                  for(Iterator iterator = childTypes.keySet().iterator(); iterator.hasNext();)
{
                      String s = (String)iterator.next();
                      int number = ((DConfigBean[])childTypes.get(s)).length;
                      out.println(indent+"+ "+s+" ("+number+" entr"+(number == 1 ? "y" : "ies")+")");
                  }
              }
              childProps = getChildProperties(info.getPropertyDescriptors());
              for(int i = 0; i < childProps.length; i++) {
                  PropertyDescriptor prop = childProps[i];
                  if(prop instanceof IndexedPropertyDescriptor) {
                      int number = ((Object[])prop.getReadMethod().invoke(bean, new Object[0])).length;
                      out.println(indent+"+ "+prop.getDisplayName()+" ("+number+" entr"+(number
== 1 ? "y" : "ies")+")");
                  } else {
                      out.println(indent+"+ "+prop.getDisplayName()+" (child property)");
                  }
              }
              out.println();
  
              // Load properties todo: handle properties of type bean but not DConfigBean
and indexed properties
              count = 0;
              properties = getNormalProperties(info.getPropertyDescriptors());
              readOnly = getReadOnly(info.getPropertyDescriptors());
              for(int i = 0; i < readOnly.length; i++) {
                  PropertyDescriptor property = readOnly[i];
                  out.println(property.getDisplayName()+": "+property.getReadMethod().invoke(bean,
new Object[0]));
              }
              if(properties.length > 0) {
                  out.println("Properties for "+getFullName(bean)+":");
              }
              for(int i = 0; i < properties.length; i++) {
                  PropertyDescriptor property = properties[i];
                  out.println("  "+(++count)+": "+property.getDisplayName()+" ("+property.getReadMethod().invoke(bean,
new Object[0])+")");
              }
              out.flush();
  
              // Auto-navigate
              if(properties.length == 0 && childTypes.size() == 1 && childProps.length
== 0) {
                  DConfigBean[] children = (DConfigBean[])childTypes.values().iterator().next();
                  if(children.length == 1) {
                      if(forward) {
                          out.println("Nothing interesting to do here.  Moving on.");
                          beans.push(children[0]);
                          continue;
                      } else if(beans.size() > 1) {
                          out.println("Nothing interesting to do here.  Moving on.");
                          beans.pop();
                          continue;
                      }
                  }
              } else if(properties.length == 0 && childTypes.size() == 0 &&
childProps.length == 1) {
                  if(!(childProps[0] instanceof IndexedPropertyDescriptor)) {
                      if(forward) {
                          out.println("Nothing interesting to do here.  Moving on.");
                          beans.push(childProps[0].getReadMethod().invoke(bean, new Object[0]));
                          continue;
                      } else if(beans.size() > 1) {
                          out.println("Nothing interesting to do here.  Moving on.");
                          beans.pop();
                          continue;
                      }
                  }
              }
              if(properties.length > 0) {
                  out.println();
              }
  
              // Show navigation options
              out.print("Action (");
              boolean first = true;
              if(properties.length > 0) {
                  if(!first) {out.print(" / ");}
                  out.print("Edit [P]roperty");
                  first = false;
              }
              if(childTypes.size() > 0 || childProps.length > 0) {
                  if(!first) {out.print(" / ");}
                  out.print("Move [D]own");
                  first = false;
              }
              if(beans.size() > 1) {
                  if(!first) {out.print(" / ");}
                  out.print("Move [U]p");
                  first = false;
              }
              if(!first) {out.print(" / ");}
              out.print("[Q]uit");
              first = false;
              out.print("): ");
              out.flush();
              String choice = in.readLine().trim().toLowerCase();
              if(choice.equals("u")) {
                  forward = false;
                  beans.pop();
                  continue;
              } else if(choice.equals("d")) {
                  forward = true;
                  if(childTypes.size() == 0 && childProps.length == 0) {
                      log.warn("No children available here.");
                      continue;
                  } else {
                      selectChildBean(childTypes, bean, childProps);
                      continue;
                  }
              } else if(choice.equals("q")) {
                  return;
              } else if(choice.equals("p")) {
                  if(properties.length == 0) {
                      log.warn("No editable properties available here.");
                      continue;
                  } else {
                      editProperty(bean, properties);
                      continue;
                  }
              } else if(isNumber(choice)) {
                  int value = Integer.parseInt(choice);
                  if(value > 0 && value <= properties.length) {
                      editProperty(bean, properties[value-1]);
                      continue;
                  }
              }
              log.error("I don't know how to do that (yet)");
          }
      }
  
      /**
       * The user wants to edit a property.  This method figures out which one (of
       * the properties available for the bean).
       */
      private void editProperty(Object bean, PropertyDescriptor[] properties) throws IOException,
InvocationTargetException, IllegalAccessException {
          if(properties.length == 1) {
              editProperty(bean, properties[0]);
              return;
          }
          String choice = null;
          while(true) {
              out.print("Edit which property (1-"+properties.length+")? ");
              out.flush();
              choice = in.readLine();
              try {
                  int value = Integer.parseInt(choice);
                  if(value > 0 && value <= properties.length) {
                      editProperty(bean, properties[value-1]);
                      return;
                  }
              } catch(NumberFormatException e) {}
          }
      }
  
      /**
       * Manages the editing of a single property.
       */
      private void editProperty(final Object bean, final PropertyDescriptor property) throws
InvocationTargetException, IllegalAccessException, IOException {
          final PropertyEditor pe = PropertyEditors.findEditor(property.getPropertyType());
          pe.addPropertyChangeListener(new PropertyChangeListener() {
              public void propertyChange(PropertyChangeEvent evt) {
                  try {
                      property.getWriteMethod().invoke(bean, new Object[]{pe.getValue()});
                      pe.removePropertyChangeListener(this);
                  } catch(IllegalAccessException e) {
                      log.error("Not allowed to set property", e);
                  } catch(IllegalArgumentException e) {
                      log.error("Invalid value for property", e);
                  } catch(InvocationTargetException e) {
                      log.error("Exception occured while setting property", e.getTargetException());
                  }
              }
          });
          out.println("\nEditing Property "+property.getDisplayName());
          Object value = property.getReadMethod().invoke(bean, new Object[0]);
          if(value == null) {
              value = pe.getJavaInitializationString();
          }
          out.println("  Old value is: '"+value+"'");
          out.println("  Specify a new value.  Enter nothing to keep the current value.\n"
+
                      "  Type (empty) for an empty string or (null) for a null.");
          out.print("New Value: ");
          out.flush();
          String choice = in.readLine();
          if(choice.equals("")) {
              return;
          } else if(choice.equals("(null)")) {
              choice = null;
          } else if(choice.equals("(empty)")) {
              choice = "";
          }
          pe.setAsText(choice);
      }
  
      /**
       * The user wants to move to a child bean.  This method figures out which
       * one.  It may be a child DConfigBean or a child property where we don't
       * have a property editor for that property type so we treat the whole
       * thing as a child bean.
       */
      private void selectChildBean(Map types, Object bean, PropertyDescriptor[] props) throws
IOException, InvocationTargetException, IllegalAccessException, InstantiationException {
          DConfigBean[] cbs = null;
          PropertyDescriptor prop = null;
          int count;
          String choice;
          if(types.size()+props.length > 1) {
              count = 0;
              out.println("\nAvailable Children:");
              for(Iterator iterator = types.keySet().iterator(); iterator.hasNext();) {
                  String name = (String) iterator.next();
                  out.println("  ["+(++count)+"] "+name);
              }
              for(int i = 0; i < props.length; i++) {
                  out.println("  ["+(++count)+"] "+props[i].getDisplayName());
              }
              while(true) {
                  out.print("Select child type (1-"+(types.size()+props.length)+"): ");
                  out.flush();
                  choice = in.readLine();
                  try {
                      int value = Integer.parseInt(choice);
                      if(value > 0 && value <= types.size()) {
                          count = 0;
                          String key = null;
                          for(Iterator iterator = types.keySet().iterator(); iterator.hasNext()
&& count++ < value;) {
                              key = (String) iterator.next();
                          }
                          cbs = (DConfigBean[]) types.get(key);
                          if(cbs != null) {
                              break;
                          }
                      } else if(value > types.size() && value <= (types.size()+props.length))
{
                          prop = props[value-types.size()-1];
                          break;
                      }
                  } catch(NumberFormatException e) {}
              }
          } else {
              if(types.size() == 1) {
                  cbs = (DConfigBean[])types.values().iterator().next();
              } else if(props.length == 1) {
                  prop = props[0];
              } else {
                  log.error("You've confused me.  Please try again.");
              }
          }
          if(cbs != null) {
              selectChildDConfigBean(cbs);
          } else if(prop != null) {
              selectChildProperty(bean, prop);
          }
      }
  
      /**
       * It turns out the user wants navigate to a child property (where we don't
       * have an editor for the property type, so we treat it as a child bean).
       * If the is a plain property, this method will just go there.  If it's an
       * indexed property, this method presents CRUD options.
       */
      private void selectChildProperty(Object bean, PropertyDescriptor prop) throws InvocationTargetException,
IllegalAccessException, IOException, InstantiationException {
          //todo: consider handling indexed properties that are themselves arrays?
          if(!(prop instanceof IndexedPropertyDescriptor)) {
              beans.push(prop.getReadMethod().invoke(bean, new Object[0]));
              return;
          }
          String choice;
          Object[] values;
          while(true) {
              out.println("\nEditing list of "+prop.getDisplayName());
              values = (Object[]) prop.getReadMethod().invoke(bean, new Object[0]);
              if(values.length == 0) {
                  out.println("  (list is currently empty)");
              }
              for(int i = 0; i < values.length; i++) {
                  out.println("  "+(i+1)+": "+values[i]);
              }
              out.print("Action ([C]reate entry");
              if(values.length > 0) {
                  out.print(" / [D]elete entry / edit entry [1"+(values.length > 1 ? "-"+values.length
: "")+"]");
              }
              out.print(" / [B]ack): ");
              out.flush();
              choice = in.readLine().trim().toLowerCase();
              if(choice.equals("c")) {
                  Object[] newv = (Object[])java.lang.reflect.Array.newInstance(values.getClass().getComponentType(),
values.length+1);
                  System.arraycopy(values, 0, newv, 0, values.length);
                  newv[values.length] = values.getClass().getComponentType().newInstance();
                  prop.getWriteMethod().invoke(bean, new Object[]{newv});
                  continue;
              } else if(choice.equals("b")) {
                  return;
              } else if(isNumber(choice)) {
                  int number = Integer.parseInt(choice);
                  if(number > 0 && number <= values.length) {
                      beans.push(values[number-1]);
                      return;
                  }
              } else {
                  log.warn("I didn't understand that");
              }
          }
      }
  
      /**
       * Checks whether a value entered by the user is composed entirely of digits.
       */
      private boolean isNumber(String choice) {
          for(int i=0; i<choice.length(); i++) {
              if(!Character.isDigit(choice.charAt(i))) {
                  return false;
              }
          }
          return choice.length() > 0;
      }
  
      /**
       * It turns out the user wants to edit a child DConfigBean.  So far, we just
       * know what type of child bean they want (e.g. "one of the resource
       * references").  This method figures out which specific instance of that
       * they want to edit (identify a specific resource reference).
       */
      private void selectChildDConfigBean(DConfigBean[] cbs) throws IOException {
          String choice;
          if(cbs.length == 1) {
              beans.push(cbs[0]);
              return;
          }
          out.println("\nAvailable Children:");
          for(int i = 0; i < cbs.length; i++) {
              out.println("  ["+(i+1)+"] "+cbs[i]);
          }
          while(true) {
              out.print("Select child (1-"+cbs.length+"): ");
              out.flush();
              choice = in.readLine();
              try {
                  int value = Integer.parseInt(choice);
                  if(value > 0 && value <= cbs.length) {
                      beans.push(cbs[value-1]);
                      break;
                  }
              } catch(NumberFormatException e) {}
          }
      }
  
      /**
       * Displays the user's current position in the stack of beans.  This
       * method shows everything down to the current position.  The caller
       * must add on the children of the current node.
       *
       * @return The String full of spaces representating the indentation
       *         for any children of the last bean displayed.
       */
      private String printLocation() throws IntrospectionException {
          out.println("          ---------- Editing Server-Specific DD ----------        
 ");
          String here = "";
          int count = 0;
          for(Iterator iterator = beans.iterator(); iterator.hasNext();) {
              ++count;
              Object temp = iterator.next();
              if(!here.equals("")) {
                  out.print(here);
                  out.print("+ ");
              }
              if(count == beans.size()) {out.print("[[[ ");}
              out.print(getFullName(temp));
              if(count == beans.size()) {out.print(" ]]]");}
              here = here + "  ";
              out.println();
          }
          return here;
      }
  
      /**
       * Gets the name of a class of beans (e.g. "Resource Reference")
       * followed by the description of the specific instances (e.g.
       * jdbc/SomeDatabase).
       */
      private String getFullName(Object bean) throws IntrospectionException {
          String name = bean.toString();
          if(name.length() > 40 || name.indexOf("@") > 0) {//todo: check whether toString
has been overridden
              name = "";
          } else {
              name = " ("+name+")";
          }
          return Introspector.getBeanInfo(bean.getClass()).getBeanDescriptor().getDisplayName()+name;
      }
  
      /**
       * Gets the sub-list of the supplied properties that are readable, writable,
       * have a property editor, and are not on the list to specifically exclude.
       */
      private PropertyDescriptor[] getNormalProperties(PropertyDescriptor[] descriptors) {
          List list = new ArrayList(descriptors.length);
          for(int i = 0; i < descriptors.length; i++) {
              PropertyDescriptor descriptor = descriptors[i];
              if(isInvisible(descriptor) || descriptor.getReadMethod() == null || descriptor.getWriteMethod()
== null || PropertyEditors.findEditor(descriptor.getPropertyType()) == null) {
                  continue;
              }
              list.add(descriptors[i]);
          }
          return (PropertyDescriptor[]) list.toArray(new PropertyDescriptor[list.size()]);
      }
  
      /**
       * Gets the sub-list of the supplied properties that are readable, not
       * writable, and are not on the list to specifically exclude.
       */
      private PropertyDescriptor[] getReadOnly(PropertyDescriptor[] descriptors) {
          List list = new ArrayList(descriptors.length);
          for(int i = 0; i < descriptors.length; i++) {
              PropertyDescriptor descriptor = descriptors[i];
              if(isInvisible(descriptor) || descriptor.getWriteMethod() != null || descriptor.getReadMethod()
== null) {
                  continue;
              }
              list.add(descriptors[i]);
          }
          return (PropertyDescriptor[]) list.toArray(new PropertyDescriptor[list.size()]);
      }
  
      /**
       * Gets the sub-list of the supplied properties that are readable, writeable,
       * and have no property editor.  These will be treated as child properties,
       * so their properties will in turn be presented for editing.
       */
      private PropertyDescriptor[] getChildProperties(PropertyDescriptor[] descriptors) {
          List list = new ArrayList(descriptors.length);
          for(int i = 0; i < descriptors.length; i++) {
              PropertyDescriptor descriptor = descriptors[i];
              if(isInvisible(descriptor) || descriptor.getWriteMethod() == null || descriptor.getReadMethod()
== null || PropertyEditors.findEditor(descriptor.getPropertyType()) != null) {
                  continue;
              }
              list.add(descriptors[i]);
          }
          return (PropertyDescriptor[]) list.toArray(new PropertyDescriptor[list.size()]);
      }
  
      /**
       * Checks whether a property is one of the ones we want to specifically
       * ignore/suppress.
       */
      private boolean isInvisible(PropertyDescriptor descriptor) {
          return descriptor.getName().equals("class") || descriptor.getName().equals("DDBean")
|| descriptor.getName().equals("xpaths");
      }
  }
  
  
  
  1.1                  incubator-geronimo/modules/core/src/java/org/apache/geronimo/console/cli/Deployer.java
  
  Index: Deployer.java
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2003 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache Geronimo" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache Geronimo", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * ====================================================================
   */
  package org.apache.geronimo.console.cli;
  
  import java.util.jar.JarFile;
  import java.io.*;
  import java.net.URLClassLoader;
  import java.net.URL;
  import java.net.MalformedURLException;
  import javax.enterprise.deploy.spi.*;
  import javax.enterprise.deploy.spi.exceptions.DeploymentManagerCreationException;
  import javax.enterprise.deploy.spi.exceptions.InvalidModuleException;
  import javax.enterprise.deploy.spi.exceptions.ConfigurationException;
  import javax.enterprise.deploy.shared.factories.DeploymentFactoryManager;
  import javax.enterprise.deploy.model.*;
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  import org.apache.geronimo.enterprise.deploy.tool.EjbDeployableObject;
  
  /**
   * Initializes a command-line JSR-88 deployer.
   *
   * @version $Revision: 1.1 $ $Date: 2003/09/04 05:26:19 $
   */
  public class Deployer {
      private static final Log log = LogFactory.getLog(Deployer.class);
      static {
          try {
              Class.forName("org.apache.geronimo.enterprise.deploy.provider.GeronimoDeploymentFactory");
          } catch(ClassNotFoundException e) {
              log.error("Unable to load Geronimo JSR-88 implementation");
          }
      }
  
      private DeploymentManager deployer;
      private DeployableObject standardModule;
      private DeploymentConfiguration serverModule;
      private PrintWriter out;
      private BufferedReader in;
      private EjbJarInfo jarInfo;
      private File saveDir = new File(System.getProperty("user.dir"));
  
      /**
       * Creates a new instance using System.out and System.in to interact with
       * the user.  The user will need ot begin by selecting an EJB JAR file
       * to work with.
       */
      public Deployer() throws IllegalStateException, IllegalArgumentException {
          this(new PrintWriter(new OutputStreamWriter(System.out), true), new BufferedReader(new
InputStreamReader(System.in)));
      }
  
      /**
       * Creates a new instance for the provided EJB JAR file using System.out
       * and System.in to interact with the user.
       */
      public Deployer(File jarFile) throws IllegalStateException, IllegalArgumentException
{
          this(jarFile, new PrintWriter(new OutputStreamWriter(System.out), true), new BufferedReader(new
InputStreamReader(System.in)));
      }
  
      /**
       * Creates a new instance using the provided input/output streams to
       * interact with the user.  The user will need ot begin by selecting an EJB
       * JAR file to work with.
       */
      public Deployer(PrintWriter out, Reader in) throws IllegalStateException, IllegalArgumentException
{
          this.out = out;
          this.in = in instanceof BufferedReader ? (BufferedReader)in : new BufferedReader(in);
          if(!connect()) {
              throw new IllegalStateException("Unable to connect to Deployment service");
          }
      }
  
      /**
       * Creates a new instance for the provided EJB JAR file and input/output
       * streams.
       */
      public Deployer(File jarFile, PrintWriter out, Reader in) throws IllegalStateException,
IllegalArgumentException {
          this.out = out;
          this.in = in instanceof BufferedReader ? (BufferedReader)in : new BufferedReader(in);
          try {
              jarInfo = new EjbJarInfo();
              jarInfo.file = jarFile;
              jarInfo.jarFile = new JarFile(jarFile);
          } catch(IOException e) {
              throw new IllegalArgumentException(jarFile+" is not a valid JAR file!");
          }
          if(!connect() || !initializeEjbJar()) {
              throw new IllegalStateException("Unable to connect to Deployment service or
prepare deployment information");
          }
      }
  
      /**
       * Enters the deployment user interface.  When this method returns, the
       * user has finished their deployment activities.
       */
      public void run() {
          workWithoutModule();
          deployer.release();
      }
  
      /**
       * Prompts the user to enter a Deployer URL and then gets a DeploymentManager
       * for that URL.
       *
       * @return <tt>true</tt> if the connection was successful.
       */
      private boolean connect() {
          out.println("\n\nEnter the deployer URL.  Leave blank for the default URL 'deployer:geronimo:'");
          out.print("URL: ");
          out.flush();
          try {
              String url = in.readLine();
              if(url.equals("")) {
                  url = "deployer:geronimo:";
              }
              deployer = DeploymentFactoryManager.getInstance().getDisconnectedDeploymentManager(url);
          } catch(DeploymentManagerCreationException e) {
              log.error("Can't create deployment manager",e);
              return false;
          } catch(IOException e) {
              log.error("Unable to read user input", e);
              return false;
          }
          return true;
      }
  
      /**
       * Loads the deployment descriptor information from the specific EJB JAR
       * file.
       *
       * @return <tt>true</tt> if the deployment information was loaded
       *         successfully.
       */
      private boolean initializeEjbJar() {
          try {
              ClassLoader loader = new URLClassLoader(new URL[]{jarInfo.file.toURL()}, ClassLoader.getSystemClassLoader());
              standardModule = new EjbDeployableObject(jarInfo.jarFile, loader);
          } catch(MalformedURLException e) {
              out.println("ERROR: "+jarInfo.file+" is not a valid JAR file!");
              return false;
          }
          try {
              serverModule = deployer.createConfiguration(standardModule);
          } catch(InvalidModuleException e) {
              out.println("ERROR: Unable to initialize a Geronimo DD for EJB JAR "+jarInfo.file);
              return false;
          }
          jarInfo.ejbJar = standardModule.getDDBeanRoot();
          jarInfo.editingEjbJar = true;
          try {
              jarInfo.ejbJarConfig = serverModule.getDConfigBeanRoot(jarInfo.ejbJar);
              initializeDConfigBean(jarInfo.ejbJarConfig);
          } catch(ConfigurationException e) {
              log.error("Unable to initialize server-specific deployment information", e);
              return false;
          }
          return true;
      }
  
      /**
       * Presents a user interface to let the user take high-level deployment
       * actions.  This lets them do the things you do without reference to a
       * particular EJB JAR.
       */
      private void workWithoutModule() {
          while(true) {
              if(jarInfo != null) {
                  workWithEjbJar();
                  continue;
              }
              out.println("\n\nNo J2EE module is currently selected.");
              out.println("  -- Select one or more servers or clusters to work with"); //
DM.getTargets()
              out.println("  -- Start non-running modules on the selected servers/clusters");
              out.println("  -- Stop running modules on the selected servers/clusters");
              out.println("  -- Undeploy modules from the selected servers/clusters");
              out.println("  -- View modules on the selected servers/clusters");
              out.println("  6) Select an EJB JAR to configure, deploy, or redeploy"); //todo:
change text when other modules are supported
              out.println("  7) Disconnect from any servers.");
              String choice;
              while(true) {
                  out.print("Action ([6-7] or [Q]uit): ");
                  out.flush();
                  try {
                      choice = in.readLine().trim().toLowerCase();
                  } catch(IOException e) {
                      log.error("Unable to read user input", e);
                      return;
                  }
                  if(choice.equals("6")) {
                      selectModule();
                      break;
                  } else if(choice.equals("7")) {
                      deployer.release();
                      out.println("Released any server resources and disconnected.");
                      break;
                  } else if(choice.equals("q")) {
                      return;
                  }
              }
          }
      }
  
      /**
       * Prompts the user to select a J2EE module to work with.
       *
       * Currently handles EJB JAR modules only.
       */
      private void selectModule() {
          out.println("\nCurrent directory is "+saveDir);
          out.println("Select an EJB JAR file to load.");
          String choice;
          File file;
          while(true) {
              out.print("File Name: ");
              out.flush();
              try {
                  choice = in.readLine().trim();
              } catch(IOException e) {
                  log.error("Unable to read user input", e);
                  return;
              }
              file = new File(saveDir, choice);
              if(!file.canRead() || file.isDirectory()) {
                  out.println("ERROR: cannot read from this file.  Please try again.");
                  continue;
              }
              saveDir = file.getParentFile();
              break;
          }
  
          try {
              jarInfo = new EjbJarInfo();
              jarInfo.file = file;
              jarInfo.jarFile = new JarFile(jarInfo.file);
          } catch(IOException e) {
              out.println("ERROR: "+file+" is not a valid JAR file!");
              jarInfo = null;
              return;
          }
          if(!initializeEjbJar()) {
              jarInfo = null;
              return;
          }
      }
  
      /**
       * Presents a user interface for a user to work with an EJB JAR.
       */
      private void workWithEjbJar() {
          while(true) {
              out.println("\n\nLoaded an EJB JAR.  Working with the ejb-jar.xml deployment
descriptor.");
              out.println("  -- Edit the standard EJB deployment descriptor (ejb-jar.xml)");
              out.println("  2) Edit the corresponding server-specific deployment information");
              out.println("  3) Load a saved set of server-specific deployment information");
              out.println("  -- Save the current set of server-specific deployment information");
              out.println("  -- Edit web services deployment information");
              out.println("  -- Deploy or redeploy the JAR into the application server");
              out.println("  7) Select a new EJB JAR to work with"); //todo: adjust text when
other modules are accepted
              out.println("  8) Manage existing deployments in the server");
              String choice;
              while(true) {
                  out.print("Action ([2-3,7,8] or [Q]uit): ");
                  out.flush();
                  try {
                      choice = in.readLine().trim().toLowerCase();
                  } catch(IOException e) {
                      log.error("Unable to read user input", e);
                      return;
                  }
                  if(choice.equals("2")) {
                      editServerSpecificDD();
                      break;
                  } else if(choice.equals("3")) {
                      loadServerSpecificDD();
                      break;
                  } else if(choice.equals("4")) {
                      saveServerSpecificDD();
                      break;
                  } else if(choice.equals("7")) {
                      selectModule();
                      if(jarInfo != null) {
                          break;
                      } else {
                          return;
                      }
                  } else if(choice.equals("8")) { //todo: prompt to save if modifications
were made
                      jarInfo = null;
                      return;
                  } else if(choice.equals("q")) {
                      jarInfo = null;
                      return;
                  }
              }
          }
      }
  
      /**
       * Loads the server-specific deployment information from a file on disk.
       * Note that in JSR-88, server-specific DDs are not saved in the
       * JAR/EAR/whatever.
       */
      private void loadServerSpecificDD() {
          out.println("\nCurrent directory is "+saveDir);
          out.println("Select a file name.  The server-specific deployment information for
the ");
          out.println((jarInfo.editingEjbJar ? "ejb-jar.xml" : "Web Services DD")+" will be
loaded from the file you specify.");
          String choice;
          while(true) {
              out.print("File Name: ");
              out.flush();
              try {
                  choice = in.readLine().trim();
              } catch(IOException e) {
                  log.error("Unable to read user input", e);
                  return;
              }
              File file = new File(saveDir, choice);
              if(!file.canRead() || file.isDirectory()) {
                  out.println("ERROR: cannot read from this file.  Please try again.");
                  continue;
              }
              saveDir = file.getParentFile();
              try {
                  BufferedInputStream fin = new BufferedInputStream(new FileInputStream(file));
                  DConfigBeanRoot root = serverModule.restoreDConfigBean(fin, jarInfo.editingEjbJar
? jarInfo.ejbJar : jarInfo.webServices);
                  fin.close();
                  if(jarInfo.editingEjbJar) {
                      jarInfo.ejbJarConfig = root;
                  } else {
                      jarInfo.webServicesConfig = root;
                  }
                  out.println("Deployment information loaded from "+file.getName());
                  return;
              } catch(IOException e) {
                  log.error("Unable to read from file", e);
                  return;
              } catch(ConfigurationException e) {
                  out.println("ERROR: "+e.getMessage());
                  return;
              }
          }
      }
  
      /**
       * Saves the server-specific deployment information to a file on disk.
       * Note that in JSR-88, server-specific DDs are not saved in the
       * JAR/EAR/whatever.
       */
      private void saveServerSpecificDD() {
          out.println("\nCurrent directory is "+saveDir);
          out.println("Select a file name.  The server-specific deployment information for
the ");
          out.println((jarInfo.editingEjbJar ? "ejb-jar.xml" : "Web Services DD")+" will be
saved to the file you specify.");
          String choice;
          try {
              while(true) {
                  out.print("File Name: ");
                  out.flush();
                      choice = in.readLine().trim();
                  File file = new File(saveDir, choice);
                  if((file.exists() && !file.canWrite()) || (!file.exists() &&
!file.getParentFile().canWrite()) || file.isDirectory()) {
                      out.println("ERROR: cannot write to this file.  Please try again.");
                      continue;
                  }
                  if(file.exists()) {
                      out.print("File already exists.  Overwrite (Y/N)? ");
                      out.flush();
                      choice = in.readLine().trim().toLowerCase();
                      if(choice.equals("n")) { // todo: makre sure they entered y or n
                          continue;
                      }
                  }
                  saveDir = file.getParentFile();
                  try {
                      BufferedOutputStream fout = new BufferedOutputStream(new FileOutputStream(file));
                      serverModule.saveDConfigBean(fout, jarInfo.editingEjbJar ? jarInfo.ejbJarConfig
: jarInfo.webServicesConfig);
                      fout.close();
                      out.println("Deployment information saved to "+file.getName());
                      return;
                  } catch(IOException e) {
                      log.error("Unable to write to file", e);
                      return;
                  } catch(ConfigurationException e) {
                      out.println("ERROR: "+e.getMessage());
                      return;
                  }
              }
          } catch(IOException e) {
              log.error("Unable to read user input", e);
              return;
          }
      }
  
      /**
       * Marches recursively through the DConfigBean tree to initialize
       * DConfigBeans for all the interesting DDBeans.  Once this is done, and
       * DDBean changes need to be relayed to the DConfigBeans that listn on them.
       */
      private void initializeDConfigBean(DConfigBean dcb) throws ConfigurationException {
          String[] xpaths = dcb.getXpaths();
          for(int i=0; i<xpaths.length; i++) {
              DDBean[] ddbs = dcb.getDDBean().getChildBean(xpaths[i]);
              for(int j = 0; j < ddbs.length; j++) {
                  initializeDConfigBean(dcb.getDConfigBean(ddbs[j]));
              }
          }
      }
  
      /**
       * Hands over control to {@link DConfigBeanConfigurator} to let the user edit
       * the server-specific deployment information.
       */
      private void editServerSpecificDD() {
          new DConfigBeanConfigurator(jarInfo.ejbJarConfig, out, in).configure();
      }
  
      /**
       * Holds all the relevent data for an EJB JAR.
       */
      private static class EjbJarInfo {
          public File file;
          public JarFile jarFile;
          public DDBeanRoot ejbJar;
          public DConfigBeanRoot ejbJarConfig;
          public DDBeanRoot webServices;
          public DConfigBeanRoot webServicesConfig;
          public boolean editingEjbJar;
      }
  }
  
  
  

Mime
View raw message