
org.mobicents.tools.twiddle.jslee.ProfileEditCommand Maven / Gradle / Ivy
The newest version!
/*
* TeleStax, Open Source Cloud Communications
* Copyright 2011-2017, Telestax Inc and individual contributors
* by the @authors tag.
*
* This program is free software: you can redistribute it and/or modify
* under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation; either version 3 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see
*/
package org.mobicents.tools.twiddle.jslee;
import gnu.getopt.Getopt;
import gnu.getopt.LongOpt;
import java.io.PrintWriter;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.slee.Address;
import javax.slee.AddressPlan;
import org.jboss.console.twiddle.command.CommandContext;
import org.jboss.console.twiddle.command.CommandException;
import org.jboss.logging.Logger;
import org.mobicents.tools.twiddle.AbstractSleeCommand;
import org.mobicents.tools.twiddle.Utils;
import org.mobicents.tools.twiddle.op.AbstractOperation;
/**
* Command performs operation on specific profile object.
* @author baranowb
*
*/
public class ProfileEditCommand extends AbstractSleeCommand {
//TODO: add bussines method calls
private ObjectName PROFILE_PROVISIONING_MBEAN;
/**
*/
public ProfileEditCommand() {
super("profile.edit", "This command performs operations on JSLEE Profile MBean like: javax.slee.profile:type=Profile,profileTableName=CallControl,profileName=");
try {
this.PROFILE_PROVISIONING_MBEAN = new ObjectName(Utils.SLEE_PROFILE_PROVISIONING); //damn annoying.
} catch (MalformedObjectNameException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NullPointerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/* (non-Javadoc)
* @see org.mobicents.tools.twiddle.AbstractSleeCommand#displayHelp()
*/
@Override
public void displayHelp() {
PrintWriter out = context.getWriter();
out.println(desc);
out.println();
//out.println("usage: " + name + " <-tprofileTableName> [-pprofileName] *");
out.println("usage: " + name + " <-operation[[arg] | [--option[=arg]]]*>");
//out.println("This command requires atleast option -t to specify table name. If -p is not used, it performs operations on defualt profiles.");
out.println();
//out.println("config:");
//out.println(" -t, --table Specifies table name from which profile should be accessed. Requires table name as argument.");
//out.println(" -p, --profile Specifies profile name of profile to be accessed. Requires profile name as argument.");
out.println("operation:");
out.println(" -l, --list Returns list of available attributes and information associated with each.");
out.println(" -d, --dirty Returns indication if profile is dirty. Does not require argument.");
//isProfileDirty()
out.println(" -w, --write Returns indication if profile is in write mode. Does not require argument.");
//isProfileWriteable()
out.println(" -e, --edit Marks profile as editable. Without this op any other will fail. Does not require argument.");
//editProfile()
out.println(" -c, --commit Commits changes done to profile. Can be invoked only after \"-e\". Does not require argument.");
//commitProfile()
out.println(" -r, --restore Revokes changes done to profile. Can be invoked only after \"-e\". Does not require argument.");
//restoreProfile()
out.println(" -o, --close De-registers MBean. Does not require argument.");
//closeProfile()
out.println(" -g, --get Returns value of profile attribute. Requires attribute name, ie. : \"voiceMailEnabled\".");
out.println(" -s, --set Sets value of profile attribute. Supports mandatory options:.");
out.println(" --name Specifies name of profile attribute. Requires attribute name as parameter.");
out.println(" --separator Specifies separator for parsing profile attribute value and creating arrays. Does not require separator as parameter if profile attribute value is not array.");
out.println(" --value Specifies string representation of profile attribute value. Requires value as parameter.");
out.println(" Command tries locally registered JMX Editor to parse value and optimize call, if editor is not found");
out.println(" it dispatches call in hope that server side has better luck.");
//out.println(" -b, --business Sets value of profile attribute. Supports mandatory options:.");
//out.println(" --method Specifies business method name. Requires method name as parameter.");
//out.println(" --name Specifies name of profile attribute. Requires attribute name as parameter.");
//out.println(" --value Specifies string representation of profile attribute value. Requires value as parameter.");
//out.println(" Command tries locally registered JMX Editor to parse value and optimize call, if editor is not found");
//out.println(" it dispatches call in hope that server side has better luck.");
out.println("Examples: ");
out.println("");
out.println(" 1. Check if profile has been edited:");
out.println("" + name + " CallControl mobile.user -w");
out.println("");
out.println(" 2. Check if any changes were introduced to profile:");
out.println("" + name + " CallControl mobile.user -d");
out.println("");
out.println(" 3. Start editing:");
out.println("" + name + " CallControl mobile.user -e");
out.println("");
out.println(" 4. Set attribute:");
out.println("" + name + " CallControl mobile.user -s --name=userPhone --value=sip:[email protected]:5090");
out.println("");
out.println(" 5. Set attribute with array:");
out.println("" + name + " CallControl mobile.user -s --name=users --separator=\";\" --value=\"Bob;Alice;John\"");
out.println("");
out.println(" 6. Commit changes:");
out.println("" + name + " CallControl mobile.user -c");
out.flush();
}
////////////////////////
// Command essentials //
////////////////////////
private static final String OPERATION_DEFAULT_GET ="getDefaultProfile";
private static final String OPERATION_GET ="getProfile";
//object name for profile
private ObjectName specificObjectName;
//table name
private String profileTableName;
//profile name
private String profileName;
//info about bean. we will use it to get type of args, check editors etc.
private MBeanInfo beanInfo;
////////////////////////
// Set essentials //
////////////////////////
//list of fields, so we know what type they are?
/* (non-Javadoc)
* @see org.mobicents.tools.twiddle.AbstractSleeCommand#getBeanOName()
*/
@Override
public ObjectName getBeanOName() throws MalformedObjectNameException, NullPointerException {
//tricky, its kind of dynamic :)
//we get it from ProfileProvisioningMBean, we could create it by hand, but there is no need for that, since
//user calls this, it indicates there is interest in editing
return specificObjectName;
}
/* (non-Javadoc)
* @see org.mobicents.tools.twiddle.AbstractSleeCommand#processArguments(java.lang.String[])
*/
@Override
protected void processArguments(String[] args) throws CommandException {
//first, we must get atleast -t, possibly -p, depending on those we call different method on ProfileProvisioningMBean
//String sopts = ":t:p:ldwecrog:s";
String sopts = "-:ldwecrog:s";
LongOpt[] lopts = {
//conf part
//new LongOpt("table", LongOpt.REQUIRED_ARGUMENT, null, 't'),
//new LongOpt("profile", LongOpt.REQUIRED_ARGUMENT, null, 'p'),
new LongOpt("noprefix", LongOpt.NO_ARGUMENT, null, 0x1000),
//operration part
new LongOpt("list", LongOpt.NO_ARGUMENT, null, 'l'),
new LongOpt("dirty", LongOpt.NO_ARGUMENT, null, 'd'),
new LongOpt("write", LongOpt.NO_ARGUMENT, null, 'w'),
new LongOpt("edit", LongOpt.NO_ARGUMENT, null, 'e'),
new LongOpt("commit", LongOpt.NO_ARGUMENT, null, 'c'),
new LongOpt("restore", LongOpt.NO_ARGUMENT, null, 'r'),
new LongOpt("close", LongOpt.NO_ARGUMENT, null, 'o'),
//get,set,bussines
new LongOpt("get", LongOpt.REQUIRED_ARGUMENT, null, 'g'),
new LongOpt("set", LongOpt.NO_ARGUMENT, null, 's'),
//options for set
new LongOpt("name", LongOpt.REQUIRED_ARGUMENT, null, SetAttributeOperation.name),
new LongOpt("separator", LongOpt.OPTIONAL_ARGUMENT, null, SetAttributeOperation.separator),
new LongOpt("value", LongOpt.OPTIONAL_ARGUMENT, null, SetAttributeOperation.value),
//new LongOpt("bussines", LongOpt.NO_ARGUMENT, null, 'b'),
};
Getopt getopt = new Getopt(null, args, sopts, lopts);
getopt.setOpterr(false);
int nonOptArgIndex = 0;
int code;
while ((code = getopt.getopt()) != -1) {
switch (code) {
case ':':
throw new CommandException("Option requires an argument: " + args[getopt.getOptind() - 1]);
case '?':
throw new CommandException("Invalid (or ambiguous) option: " + args[getopt.getOptind() - 1]);
//CONF PART
// case 't':
// this.profileTableName = getopt.getOptarg();
// break;
// case 'p':
// this.profileName = getopt.getOptarg();
// break;
// OPERATION PART
case 0x1000:
break;
case 1:
//non opt args, table and profile name(maybe)
switch(nonOptArgIndex)
{
case 0:
profileTableName = getopt.getOptarg();
nonOptArgIndex++;
break;
case 1:
profileName = getopt.getOptarg();
nonOptArgIndex++;
break;
default:
throw new CommandException("Command: \"" + getName() + "\" expects at most two non opt arguments!");
}
break;
case 'l':
//list
super.operation = new ListOperation(super.context, super.log, this);
prepareCommand();
super.operation.buildOperation(getopt, args);
break;
case 'd':
//dirt
super.operation = new SimpleInvokeOperation(super.context, super.log, this,"isProfileDirty");
prepareCommand();
super.operation.buildOperation(getopt, args);
break;
case 'w':
//write
super.operation = new SimpleInvokeOperation(super.context, super.log, this,"isProfileWriteable");
prepareCommand();
super.operation.buildOperation(getopt, args);
break;
case 'e':
//edit
super.operation = new SimpleInvokeOperation(super.context, super.log, this,"editProfile");
prepareCommand();
super.operation.buildOperation(getopt, args);
break;
case 'c':
//commit
super.operation = new SimpleInvokeOperation(super.context, super.log, this,"commitProfile");
prepareCommand();
super.operation.buildOperation(getopt, args);
break;
case 'r':
//restore
super.operation = new SimpleInvokeOperation(super.context, super.log, this,"restoreProfile");
prepareCommand();
super.operation.buildOperation(getopt, args);
break;
case 'o':
//close
super.operation = new SimpleInvokeOperation(super.context, super.log, this,"closeProfile");
prepareCommand();
super.operation.buildOperation(getopt, args);
break;
case 'g':
//get
super.operation = new GetAttributeOperation(super.context, super.log, this);
prepareCommand();
super.operation.buildOperation(getopt, args);
break;
case 's':
//set
super.operation = new SetAttributeOperation(super.context, super.log, this);
prepareCommand();
super.operation.buildOperation(getopt, args);
break;
// case 'b':
// //bussines
// super.operation = new BussinesMethodOperation(super.context, super.log, this);
// super.operation.buildOperation(getopt, args);
// break;
default:
throw new CommandException("Command: \"" + getName() + "\", found unexpected opt: " + args[getopt.getOptind() - 1]);
}
}
}
private void prepareCommand() throws CommandException
{
//get bean name and bean info.
if(profileTableName == null)
{
throw new CommandException("Command: \"" + getName() + "\", expects atleast \"-t\" to specify table name!");
}
String getOperationName;
String[] sig;
Object[] parms;
MBeanServerConnection server = super.context.getServer();
if(profileName == null)
{
//default;
getOperationName = OPERATION_DEFAULT_GET;
parms = new Object[]{profileTableName};
sig = new String[]{"java.lang.String"};
}else
{
getOperationName = OPERATION_GET;
parms = new Object[]{profileTableName, profileName};
sig = new String[]{"java.lang.String", "java.lang.String"};
}
try {
specificObjectName = (ObjectName) server.invoke(PROFILE_PROVISIONING_MBEAN, getOperationName, parms, sig);
}catch (Exception e) {
// if main operation is commitProfile and execute after createProfile
// ProfileProvisioning MBean can not execute getProfile for new profile after createProfile execution
if (this.operation.getOperationName().equals("commitProfile"))
{
try {
String profileBeanName = "javax.slee.profile:profileName=" + this.profileName;
profileBeanName += ",profileTableName=" + this.profileTableName;
profileBeanName += ",type=Profile";
specificObjectName = new ObjectName(profileBeanName);
}catch (Exception ce) {
throw new CommandException ("Command: \"" + getName()+"\" failed to commit bean name for specified profile.", ce);
}
}
else
{
throw new CommandException("Command: \"" + getName()+"\" failed to obtain bean name for specified table name and profile. Table or profile does not exist.", e);
}
}
//ok, now lets get bean info;
try{
this.beanInfo = server.getMBeanInfo(specificObjectName);
}catch (Exception e) {
throw new CommandException("Command: \"" + getName()+"\" failed to obtain bean name for specified table name and profile.", e);
}
}
private MBeanAttributeInfo findAttribute(String attr_name,
MBeanAttributeInfo[] attribute_info)
{
for (int i = 0; i < attribute_info.length; i++)
{
MBeanAttributeInfo mBeanAttributeInfo = attribute_info[i];
if (mBeanAttributeInfo.getName().equals(attr_name))
return mBeanAttributeInfo;
}
return null;
}
private class ListOperation extends AbstractOperation {
public ListOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand) {
super(context, log, sleeCommand);
//not set, since its complicated :)
}
@Override
public void buildOperation(Getopt opts, String[] args) throws CommandException {
//nothing
}
@Override
public void invoke() throws CommandException {
try {
//we dont need to invoke anything, we have everything already :)
displayResult();
} catch (Exception e) {
//add handle error here?
throw new CommandException("Failed to invoke \"" + this.operationName + "\" due to: ", e);
}
}
/* (non-Javadoc)
* @see org.mobicents.tools.twiddle.op.AbstractOperation#displayResult()
*/
@Override
public void displayResult() {
if (!context.isQuiet()) {
Set notDisplayed = new HashSet();
notDisplayed.add("ProfileDirty");
notDisplayed.add("ProfileWriteable");
// Translate the result to text
String resultText = null;
PrintWriter out = context.getWriter();
//dont look at operationResult, we want info
if (beanInfo != null) {
MBeanAttributeInfo[] infos = beanInfo.getAttributes();
for(MBeanAttributeInfo info:infos)
{
if(notDisplayed.contains(info.getName()))
{
//skip
continue;
}
out.println();
//out.println("Class: "+info.getClass());
out.println("Desc : "+info.getDescription());
out.println("Name : "+info.getName());
out.println("Type : "+info.getType());
out.println("r/w : "+info.isReadable()+"/"+info.isWritable());
out.println("isIs : "+info.isIs()); // LOL :)
}
} else {
resultText = "'success'";
out.println(resultText);
}
// render results to out
out.flush();
}
}
}
/**
* Simple op to invoke some non arg methods.
* @author baranowb
*
*/
private class SimpleInvokeOperation extends AbstractOperation {
public SimpleInvokeOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand,String operationName) {
super(context, log, sleeCommand);
super.operationName = operationName;
}
@Override
public void buildOperation(Getopt opts, String[] args) throws CommandException {
}
}
private class GetAttributeOperation extends AbstractOperation {
//private String attributeName;
//so we can access MBean info.
private ProfileEditCommand editCommand;
public GetAttributeOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand) {
super(context, log, sleeCommand);
//name is derived from type of attribute, usually its "get", but in case MBean info will reveal bool, it will be "is"
//command for bean info
this.editCommand = (ProfileEditCommand) sleeCommand;
}
@Override
public void buildOperation(Getopt opts, String[] args) throws CommandException {
String attributeName = opts.getOptarg();
//now we have to build name of command.
MBeanAttributeInfo info = findAttribute(attributeName, editCommand.beanInfo.getAttributes());
if(info == null)
{
throw new CommandException("Attribute: "+attributeName+", does not exist in bean!");
}
if(!info.isReadable())
{
throw new CommandException("Attribute: "+attributeName+", is not readable!");
}
if(info.isIs())
{
super.operationName = "is"+attributeName;
}else
{
super.operationName = "get"+attributeName;
}
}
}
private class SetAttributeOperation extends AbstractOperation {
//TODO: allow no value to indicate set(null);
public static final char name = 'n';
public static final char separator = 'p';
public static final char value = 'v';
private String attributeName;
private String valueSeparator;
private String stringAttributeValue;
//so we can access MBean info.
private ProfileEditCommand editCommand;
public SetAttributeOperation(CommandContext context, Logger log, AbstractSleeCommand sleeCommand) {
super(context, log, sleeCommand);
//name is derived from type of attribute, usually its "get", but in case MBean info will reveal bool, it will be "is"
//command for bean info
this.editCommand = (ProfileEditCommand) sleeCommand;
}
@Override
public void buildOperation(Getopt opts, String[] args) throws CommandException {
int code;
while ((code = opts.getopt()) != -1) {
switch (code) {
case ':':
throw new CommandException("Option requires an argument: " + args[opts.getOptind() - 1]);
case '?':
throw new CommandException("Invalid (or ambiguous) option: " + args[opts.getOptind() - 1] + " --> " + opts.getOptopt());
case name:
attributeName = opts.getOptarg();
break;
case separator:
//this can be empty.
valueSeparator = opts.getOptarg();
break;
case value:
//this can be empty.
stringAttributeValue = opts.getOptarg();
break;
default:
throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
+ "\", found unexpected opt: " + args[opts.getOptind() - 1]);
}
}
if(attributeName == null)
{
throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
+ "\", requiers \"--name\".");
}
// if(stringAttributeValue == null)
// {
// throw new CommandException("Operation \"" + this.operationName + "\" for command: \"" + sleeCommand.getName()
// + "\", requiers \"--value\".");
// }
MBeanAttributeInfo info = findAttribute(attributeName, editCommand.beanInfo.getAttributes());
//hmm
super.operationName = "set" + info.getName();
if (valueSeparator != null) {
Class arrayClazz;
Class valueClazz;
try {
arrayClazz = Class.forName(info.getType());
if (arrayClazz.isArray()) {
valueClazz = arrayClazz.getComponentType();
} else {
throw new CommandException("Attribute type is not array and separator is not used.");
}
} catch (ClassNotFoundException e) {
throw new CommandException("Class is not found for attribute type.");
}
if (valueSeparator.length() > 1) {
throw new CommandException("Separator must contains only single character.");
}
String delims = "["+valueSeparator+"]";
String[] tokens = stringAttributeValue.split(delims);
Object array = Array.newInstance(valueClazz, tokens.length);
for (int i=0; i
© 2015 - 2025 Weber Informatics LLC | Privacy Policy