/**
* Executer.java
*
* Copyright 2012 Niolex, Inc.
*
* Niolex licenses this file to you 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.apache.niolex.commons.remote;
import static org.apache.niolex.commons.remote.ConnectionWorker.endl;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import org.apache.niolex.commons.codec.StringUtil;
import org.apache.niolex.commons.reflect.FieldUtil;
import org.apache.niolex.commons.reflect.ItemNotFoundException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
/**
* Execute commands from client.
*
* @author <a href="mailto:xiejiyun@gmail.com">Xie, Jiyun</a>
* @version 1.0.0
* @since 2012-7-25
*/
public abstract class Executer {
// can reuse, share globally
private static final ObjectMapper mapper;
static {
/**
* Init the Object Mapper as follows.
*/
mapper = new ObjectMapper();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
/**
* Write the string to the output stream and flush the output stream.
*
* @param out the output stream
* @param s the string to be written
* @throws IOException if I/O related error occurred
*/
protected static void writeAndFlush(OutputStream out, String s) throws IOException {
out.write(StringUtil.strToUtf8Byte(s));
out.flush();
}
/**
* Execute the command on the object.
*
* @param o the target object
* @param out the output stream
* @param args The command line parsed from client input
* It's of the following format:<pre>
* Index Explain
* 0 Command Name
* 1 Object Path
* 2 Extension Argument 1 (Optional)
* 3 Extension Argument 2 (Optional)</pre>
* @throws IOException if I/O related error occurred
*/
public abstract void execute(Object o, OutputStream out, String[] args) throws IOException;
/**
* Get bean details.
*
* @author <a href="mailto:xiejiyun@gmail.com">Xie, Jiyun</a>
* @version 1.0.0
* @since 2012-7-25
*/
public static class Getter extends Executer {
/**
* {@inheritDoc}
*
* Override super method
* @see org.apache.niolex.commons.remote.Executer#execute(java.lang.Object, java.io.OutputStream, java.lang.String[])
*/
@Override
public void execute(Object o, OutputStream out, String[] args) throws IOException {
writeAndFlush(out, mapper.writeValueAsString(o) + endl());
}
}
/**
* List all the fields in any bean.
*
* @author <a href="mailto:xiejiyun@gmail.com">Xie, Jiyun</a>
* @version 1.0.0
* @since 2012-7-25
*/
public static class Lister extends Executer {
/**
* {@inheritDoc}
*
* Override super method
* @see org.apache.niolex.commons.remote.Executer#execute(java.lang.Object, java.io.OutputStream, java.lang.String[])
*/
@Override
public void execute(Object o, OutputStream out, String[] args) throws IOException {
Field[] fields = o.getClass().getDeclaredFields();
StringBuilder sb = new StringBuilder();
sb.append("All Fields Of ").append(o.getClass().getSimpleName()).append(endl());
for (Field f : fields) {
sb.append(" ").append(f.getName()).append(endl());
}
sb.append("---").append(endl());
writeAndFlush(out, sb.toString());
}
}
/**
* Set bean properties.
*
* @author <a href="mailto:xiejiyun@gmail.com">Xie, Jiyun</a>
* @version 1.0.0
* @since 2012-7-25
*/
public static class Setter extends Executer {
/**
* {@inheritDoc}
*
* Override super method
* @see org.apache.niolex.commons.remote.Executer#execute(java.lang.Object, java.io.OutputStream, java.lang.String[])
*/
@Override
public void execute(Object o, OutputStream out, String[] args) throws IOException {
if (args.length != 4) {
writeAndFlush(out, "Invalid Command." + endl());
return;
}
try {
FieldUtil.setValueAutoConvert(o, args[2], args[3]);
writeAndFlush(out, "Set Field Success." + endl());
} catch (ItemNotFoundException e) {
writeAndFlush(out, "Field Not Found." + endl());
} catch (UnsupportedOperationException e) {
writeAndFlush(out, e.getMessage() + endl());
} catch (Exception e) {
writeAndFlush(out, "Failed to Set Field:" + e.getMessage() + "." + endl());
}
}
}
/**
* Invoke method on target object.
*
* @author <a href="mailto:xiejiyun@gmail.com">Xie, Jiyun</a>
* @version 1.0.0
* @since 2012-7-26
*/
public static class Invoker extends Executer {
/**
* {@inheritDoc}
*
* Override super method
* @see org.apache.niolex.commons.remote.Executer#execute(java.lang.Object, java.io.OutputStream, java.lang.String[])
*/
@Override
public void execute(Object o, OutputStream out, String[] args) throws IOException {
StringBuilder sb = new StringBuilder();
if (o instanceof Invokable) {
((Invokable)o).invoke(out, args);
} else if (o instanceof Runnable) {
((Runnable)o).run();
} else {
sb.append("Target ").append(o.getClass().getSimpleName());
sb.append(" Is not Allowed to Invoke.");
sb.append(endl());
writeAndFlush(out, sb.toString());
return;
}
sb.append("---Invoke Success---").append(endl());
writeAndFlush(out, sb.toString());
}
}
/**
* Invoke the methods on instance of {@link org.apache.niolex.commons.remote.Monitor}
*
* @author <a href="mailto:xiejiyun@gmail.com">Xie, Jiyun</a>
* @version 1.0.5, $Date: 2012-11-23$
*/
public static class InvoMonitor extends Executer {
/**
* {@inheritDoc}
*
* Override super method
* @see org.apache.niolex.commons.remote.Executer#execute(java.lang.Object, java.io.OutputStream, java.lang.String[])
*/
@Override
public void execute(Object o, OutputStream out, String[] args) throws IOException {
if (o instanceof Monitor) {
if (args.length < 3) {
writeAndFlush(out, "Please specify the Key to Monitor." + endl());
return;
}
String parameter = args.length > 3 ? args[3] : "default";
((Monitor) o).doMonitor(out, args[2], parameter);
} else {
writeAndFlush(out, "Object is not a Monitor." + endl());
}
}
}
}