Sonic Management API and Administered Objects

Posted by Admin on 11-Mar-2010 15:50

Hi, need some help on the best approach to mirror the broker setup (factories / Administered queues and topics / user-groups / ACLs) from one broker to another. If there a tool or program that would help me do this quickly. For example, lets say I want to copy the entire [pertaining to my project only] from DEV sonic server to QA and then to Production - what is the best way of doing it (programatically with no room for errors). We were looking at using the Sonic management APIs - but I couldnt find solution on copying "Administered Objects".I can see the API com.sonicsw.mq.mgmtapi.config.IBrokerBean that helps me copy the ones under the /Brokers/MgmtBroker node - but would it work for "Administered Objects"  ? if yes, How ?

I am refering to Administered Objects => Menu Tools->JMS Administered Objects in Sonic Management Console.

All Replies

Posted by Bill Wood on 14-Mar-2010 08:56

I am not sure this is absolutely the best way, but....

Administered Objects are a normal JNDI store and have both "lookup" and "bind" capability.  The Command Line sample under /MQ/samples (I think) has the jndi lookup that shows how to:

  • list what is in a context
  • go to a sub-context

Once you have the object and its context from one store you can copy it to another.   Note that the same thing would work copying from a Sonic naming service to an external one as these are just Java javax.naming.Referenceable objects.  You won't find the administered objects under the broker bean because they are not associated with a broker.  They are just standard ConnectionFactories and Destinations (and further you could store any Referencable object in there, not just the ones that make to Sonic objects)

Here is some sample code that I borrowed that should get the basics for you.  It is a little cut and paste job, so I don't expect it to compile exactly, but it gets the basics across.

package com.progress.communities.util.jndi;

import javax.jms.ConnectionFactory;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NameClassPair;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.Referenceable;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

public class JNDICopy {
 
  protected static final Logger logger = Logger.getLogger(JNDICopy.class);
 
  protected InitialContext src_ctx  = null;
  protected InitialContext dest_ctx = null;

  public void init() {
   src_ctx = JNDIUtil.createInitialContext(
     ((JNDICopyParams)(ApplicationContext.get("params"))).getParameter(JNDICopyParams.SRCICF),
     ((JNDICopyParams)(ApplicationContext.get("params"))).getParameter(JNDICopyParams.SRCURL),
     ((JNDICopyParams)(ApplicationContext.get("params"))).getParameter(JNDICopyParams.SRCUSER),
     ((JNDICopyParams)(ApplicationContext.get("params"))).getParameter(JNDICopyParams.SRCPASSWD),
     ((JNDICopyParams)(ApplicationContext.get("params"))).getParameter(JNDICopyParams.SRCPROPS)
   );

   dest_ctx = JNDIUtil.createInitialContext(
       ((JNDICopyParams)(ApplicationContext.get("params"))).getParameter(JNDICopyParams.DESTICF),
       ((JNDICopyParams)(ApplicationContext.get("params"))).getParameter(JNDICopyParams.DESTURL),
       ((JNDICopyParams)(ApplicationContext.get("params"))).getParameter(JNDICopyParams.DESTUSER),
       ((JNDICopyParams)(ApplicationContext.get("params"))).getParameter(JNDICopyParams.DESTPASSWD),
       ((JNDICopyParams)(ApplicationContext.get("params"))).getParameter(JNDICopyParams.DESTPROPS)
     );
  }
 
  public void run() {
    if (src_ctx != null && dest_ctx != null) {
      logger.info("Trying to copy objects from Source JNDI to Destination JNDI.");
     
      processContext("");
     
      logger.info("Done.");
    }
  }
 
  public void cleanup() {
    try {
      if (src_ctx != null) {
        src_ctx.close();
      }
    } catch (Exception e) {}
   
    try {
      if (dest_ctx != null) {
        dest_ctx.close();
      }
    } catch (Exception e) {}
  }

  private void processContext(String path) {
    try {
      NamingEnumeration en = src_ctx.list(path);
      while(en.hasMoreElements()) {
        NameClassPair ncp = (NameClassPair)(en.nextElement());

        Object o = src_ctx.lookup(path + ncp.getName());
        if (o instanceof Context) {
          processContext(path + "/" + ncp.getName());
        } else {
          if (o instanceof Referenceable) {
            JNDIUtil.bindObject(o, path + ncp.getName(), dest_ctx);
          }
        }
      }
    } catch (NamingException ne) {
      logger.error("Error processing context : " + path);
      ne.printStackTrace();
    }
   
  }
 
/**
  * Helper Class to bind Objects into any JNDI repository. When the Object is
  * existing, it will be re-bound to the same lookup name.
*/
public class JNDIUtil {

  private static Logger logger = Logger.getLogger(JNDIUtil.class);

 
  public static InitialContext createInitialContext(
    String initialCFName, String url, String user, String password, String properties
  ) {
   
    InitialContext result = null;
   
    Hashtable props = new Hashtable();
   
    logger.info("Creating initial context ...");
   
    logger.info("InitialContextFactory = '" + initialCFName +"'");
    props.put(Context.INITIAL_CONTEXT_FACTORY, initialCFName);

    logger.info("ProviderURL = '" + url + "'");
    props.put(Context.PROVIDER_URL, url);
   
    if (user != null && password != null) {
      logger.info("User = '" + user + "'");
      props.put(Context.SECURITY_PRINCIPAL, user);
      logger.info("Password = '" + password + "'");
      props.put(Context.SECURITY_CREDENTIALS, password);
    }
   
    if (properties != null) {
      StringTokenizer sTok = new StringTokenizer(properties, ";");
   
      while(sTok.hasMoreTokens()) {
        String pair = sTok.nextToken();
        int pos = pair.indexOf("=");
        if (pos != -1) {
          String key = pair.substring(0, pos);
          String value = pair.substring(pos + 1);
       
          logger.info(key + " = '" + value + "'");
          props.put(key, value);
        }
      }
    }
   
    try {
      result = new InitialContext(props);
    } catch (NamingException ne) {
      logger.error("Error resolving Initial context to " + url);
      ne.printStackTrace();
    }
   
    logger.info("Initial Context created.");
    return result;
  }
 
  public static void bindObject(Object obj, String name, Context ctx) throws NamingException {
   
    if (!(obj instanceof Referenceable)) {
      logger.warn("Cant bind in JNDI: " + obj.getClass().getName() + " doesn't implement javax.naming.Referenceable");
      return;
    }
   
    logger.debug("Binding Object of type " + obj.getClass().getName() + " to " + name);
    if(name.startsWith("/"))
      name = name.substring(1);
    checkContext(ctx, name);
   
    try {
      ctx.bind(name, obj);
    } catch (NamingException ne) {
      logger.info("Object exists, rebinding...");
      ctx.rebind(name, obj);
    }
  }

  private static void checkContext(Context ctx, String name) {
    StringTokenizer sTok = new StringTokenizer(name, "/");
    if(sTok.countTokens()
      return;

    Context subCtx = null;

    String subName = sTok.nextToken();
    try{
      subCtx = (Context) ctx.lookup(subName);
    }catch(NamingException ne){
      logger.debug("Creating subContext " + subName);
      try{
        subCtx = ctx.createSubcontext(subName);
      }catch(NamingException ne2){
      }
    }catch(ClassCastException cce){
      logger.error("Context " + subName + " already bound and not a Context.");
    }
    checkContext(subCtx, name.substring(subName.length() + 1));
  }
}

  public static void main(String[] args) {
    JNDICopyParams params = new JNDICopyParams(args);
    ApplicationContext.put("params", params);

    JNDICopy jc = new JNDICopy();

    try {
      jc.init();
      jc.run();
    } catch (Exception e) {
      logger.error("main(String[])", e);
    } finally {
      jc.cleanup();
    }
  }
}

Posted by Admin on 16-Mar-2010 10:55

William, Thanks a lot this answered my question and my utility that copies the ACLs / users - groups / factories / queues-topics is all ready. I actually made it XML based and wrapped it up in ant task. Now my developers can go and just promote the XML that has what it takes to deploy the necessary sonic objects. No more have to ask Ops guys to use the sonic console - which was error prone to manual entry errors. Thanks a lot.

Posted by Admin on 20-Mar-2010 14:07

I believe you could also use an external JNDI provider such as a LDAP server.  This would allow you to quite easily import/export the settings between the environments using the command line tools.

This thread is closed