I have a class
class Message
{
public String message, sender;
public Message (String msg, String from)
{
// check here that msg and from are not null. If so, use a default value or throw an NullPointerException
message = msg;
sender = from;
}
// Just a utility method for printing out the Message to System.out
public String toString () { return sender+":"+message; }
}
I am defining in main activity
Hashtable<String, ArrayList<Message>> table = new Hashtable<String, ArrayList<Message>>();
I want to pass this table variable to another fragment.How can I do this ?
Use Interface & have custom listeners.
Communicating with Other Fragments
Related
I have an abstract class
public abstract class Sender {
private IThrottler throttler;
public final Object sendMessage(String smsText, String smsSenderName, String contactNumber) throws Exception {
tdLogger.info("sending request >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
String messageId = (String) sendSMS(smsText, smsSenderName, contactNumber);
tdLogger.info("request sent <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
return messageId;
}
public final Object throttleMessage(String smsText, String smsSenderName, String contactNumber) throws Exception {
if (throttler != null) {
throttler.acquire();
tdLogger.info("sending request >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
String messageId = (String) sendSMS(smsText, smsSenderName, contactNumber);
tdLogger.info("request sent <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
return messageId;
} else {
throw new Exception("throttler is not initialized");
}
}
public abstract Object send(String smsText, String smsSenderName, String contactNumber) throws Exception;
}
I have another class SenderImpl that which extends Sender
is there a way to force implementing the function send without giving the ability to call it directly and only be able to call sendMessage and throttleMessage to force running certain logic?
You can make the abstract send method protected so that only subclasses and classes in the same package can call it. This achieves what you intend even if it can be circumvented by placing a class in the same package.
I created an eclipse-rcp's project's plugin.xml with a new command with a parameter.
ArrayList<parameterization> parameters = new ArrayList<parameterization>();
IParameter iparam;
//get the command from plugin.xml
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
ICommandService cmdService = (ICommandService)window.getService(ICommandService.class);
Command cmd = cmdService.getCommand("org.ipiel.demo.commands.click");
//get the parameter
iparam = cmd.getParameter("org.ipiel.demo.commands.click.paramenter1");
Parameterization params = new Parameterization(iparam, "commandValue");
parameters.add(params);
//build the parameterized command
ParameterizedCommand pc = new ParameterizedCommand(cmd, parameters.toArray(new Parameterization[parameters.size()]));
//execute the command
IHandlerService handlerService = (IHandlerService)window.getService(IHandlerService.class);
handlerService.executeCommand(pc, null);
I tried this example to pass parameters and it worked.
The issue in this example that I could pass only parameters of type String. ( because Parameterization )
I want to pass parameter of hash map and in general to pass any object.
I tried this code
IServiceLocator serviceLocator = PlatformUI.getWorkbench();
ICommandService commandService = (ICommandService) serviceLocator.getService(ICommandService.class);
ExecutionEvent executionEvent = new ExecutionEvent(cmd, paramArray, null, null);
cmd.executeWithChecks(executionEvent);
but it didn't work the parameters didn't move ( it was null)
Could you please help to to move object as parameter in command ?
Since it would get confusing to add another solution to my first answer, I'll provide another one for a second solution.
The choices I gave were " A) use the selected object of the "Execution Event" (examine that, it contains a lot of infos). B) you can use AbstractSourceProvider, so you can pass your object to the application context."
A) can be used in your Handler if your object is the selection of a Structured Object like a Tree:
MyObject p = (MyObject) ((IStructuredSelection) HandlerUtil.getCurrentSelection(event)).getFirstElement();
B) The usage of a Source provider is a bit more tricky. The main idea is, that you add your object to the application context. The important snippets for Eclipse 3.x from a project that I set up after I read this blog (note: it is in german and the example it provides doesn't work):
In your plugin.xml add:
<extension point="org.eclipse.ui.services">
<sourceProvider
provider="com.voo.example.sourceprovider.PersonSourceProvider">
<variable
name="com.voo.example.sourceprovider.currentPerson"
priorityLevel="activePartId">
</variable>
</sourceProvider>
Set up your own SourceProvider. Calling the "getCurrentState" you can get the variable (your Person object in this case) of that SourceProvider:
public class PersonSourceProvider extends AbstractSourceProvider{
/** This is the variable that is used as reference to the SourceProvider
*/
public static final String PERSON_ID = "com.voo.example.sourceprovider.currentPerson";
private Person currentPerson;
public PersonSourceProvider() {
}
#Override
public void dispose() {
currentPerson = null;
}
**/**
* Used to get the Status of the source from the framework
*/
#Override
public Map<String, Person> getCurrentState() {
Map<String, Person> personMap = new HashMap<String, Person>();
personMap.put(PERSON_ID, currentPerson);
return personMap;
}**
#Override
public String[] getProvidedSourceNames() {
return new String[]{PERSON_ID};
}
public void personChanged(Person p){
if (this.currentPerson != null && this.currentPerson.equals(p)){
return;
}
this.currentPerson = p;
fireSourceChanged(ISources.ACTIVE_PART_ID, PERSON_ID, this.currentPerson);
}
}
In your View you register to the SourceProvider and set the Object to the object you want to transfer to your Handler.
public void createPartControl(Composite parent) {
viewer = new TreeViewer(parent);
viewer.setLabelProvider(new ViewLabelProvider());
viewer.setContentProvider(new ViewContentProvider());
viewer.setInput(rootPerson);
getSite().setSelectionProvider(viewer);
viewer.addSelectionChangedListener(new ISelectionChangedListener() {
#Override
public void selectionChanged(SelectionChangedEvent event) {
Person p = null;
if (event.getSelection() instanceof TreeSelection) {
TreeSelection selection = (TreeSelection) event.getSelection();
if (selection.getFirstElement() instanceof Person) {
p = (Person) selection.getFirstElement();
}
}
if (p==null) {
return;
}
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
ISourceProviderService service = (ISourceProviderService) window.getService(ISourceProviderService.class);
PersonSourceProvider sourceProvider = (PersonSourceProvider) service.getSourceProvider(PersonSourceProvider.PERSON_ID);
sourceProvider.personChanged(p);
}
});
}
And in your Handler you can just call the PersonSourceProvider#getCurrentState to get your Objects back.
Advantage of this method is, that you can use the Objectd anywhere you want. E.g. you can even set up a PropertyTester to enable/disable UI elements according to the currently selected Object.
The Parameterized Command does only accept Strings.
Here is an example for smaller objects:
Disclaimer: this is for Eclipse 3.x. I am not using Eclipse 4.x a lot, so you might have to adapt there in case you need it.
Create a Pluginproject (com.voo.example.commandparameter.advanced) with a View (com.voo.example.commandparameter.advanced.view) , a Command (com.voo.example.commandparameter.advanced.sysoCommand) with menu entry and Handler(com.voo.example.commandparameter.advanced.sysoCommand), and a universal Object (MyTestObject).
The Command needs a Parameter and a Parametertype in the plugin.xml, that gets passed to it:
<extension
point="org.eclipse.ui.commands">
<command
id="com.voo.example.commandparameter.advanced.sysoCommand"
name="SysoCommand">
<commandParameter
id="myObject"
name="object"
optional="true"
typeId="com.voo.example.commandparameter.advanced.testType">
</commandParameter>
</command>
<commandParameterType
id="com.voo.example.commandparameter.advanced.testType"
type="com.voo.example.commandparameter.advanced.MyTestObject">
</commandParameterType>
In the Object you set atrtibutes like name and street and define a convertToString method like that:
public String convertToString() {
return getName() +",,,"+ getStreet();
}
(you can override the toString method, too. I just used that method to set weired delimiters to the returned String)
And in a Class MyParamterConverter you can transfer it back:
public class MyParameterConverter extends AbstractParameterValueConverter {
public MyParameterConverter() {
}
#Override
public String convertToString(Object parameterValue)
throws ParameterValueConversionException {
return parameterValue.toString();
}
/**
* This will always create a new object. Just keep that in mind
* if you're trying to work with the objects.
*/
#Override
public Object convertToObject(String parameterValue)
throws ParameterValueConversionException {
//Split the String to get the attributes back
String delimiter =",,,";
String[] split = parameterValue.split(delimiter);
String name = split[0];
String street = split [1];
return new MyTestObject(name, street);
}
}
Now you can call the command with a buttonclick in your view, for example:
btnGo.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent event) {
MyTestObject testObject = new MyTestObject(textName.getText(),textStreet.getText());
ICommandService cS = (ICommandService)getSite().getService(ICommandService.class);
IHandlerService hS = (IHandlerService)getSite().getService(IHandlerService.class);
Command sysoComm = cS.getCommand("com.voo.example.commandparameter.advanced.sysoCommand");
HashMap<String, String> params = new HashMap<String, String>();
params.put("myObject", testObject.convertToString());
ParameterizedCommand pC = ParameterizedCommand.generateCommand(sysoComm, params);
try {
hS.executeCommand(pC, null);
} catch (Exception e) {
e.printStackTrace();
}
}
});
And the Handler can transform the passed parameters back :
public class MyObjectHandler extends AbstractHandler {
#Override
public Object execute(ExecutionEvent event) throws ExecutionException {
String param1 = event.getParameter("myObject");
MyParameterConverter converter = new MyParameterConverter();
Object convertToObject = null;
try {
convertToObject = converter.convertToObject(param1);
} catch (ParameterValueConversionException e) {
e.printStackTrace();
}
if (convertToObject instanceof MyTestObject) {
MyTestObject to = (MyTestObject) convertToObject;
System.out.println(to.toString());
}
return null;
}
}
This should work for most smaller sized objects that do not change while you pass them. If you need to pass bigger objects, you will have two choices: A) use the selected object of the "Execution Event" (examine that, it contains a lot of infos). B) you can use AbstractSourceProvider, so you can pass your object to the application context.
For a long time I have been focused on delivering an object via a command parameter. But in the end, the easiest workaround is to simply ignore the parameter stuff and put the desired object in a new child IExclipseContext and execute the command with that context. That way your handler gets your object injected.
Caller:
ECommandService commandService = // get commandService...
EHandlerService handlerService = // get handlerService...
IEclipseContext context = // get active or application context...
IEclipseContext childCtx = context.createChild();
childCtx.set(MyObject.class, instancOfMyObject);
ParameterizedCommand command = commandService.createCommand("my.command.id", null);
handlerService.executeHandler(command, childCtx);
In your handler:
#Execute
public void execute(#Optional MyObject myObject) {
if(myObject != null) {
// work with your object
}
}
Voila, no converters or callbacks (i.e. SelectionService) needed...
I am not really familiar with this as passing parameters to commands is quite rare. It looks like you have to use commandParameterType in the org.eclipse.ui.commands command definition to define code based on AbstractParameterValueConverter to convert between objects and the string for the parameter value.
I need to connect a Boolean and a String. I also need a getter and a setter for each Boolean.
For example:
boolean errorFlag1;
private static final String errorMessage1 = "...";
boolean errorFlag2;
private static final String errorMessage2 = "...";
...
public Messages[] getErrorMessages()
{
if(errorFlag1)
Add errorMessage1 to Messages[]
if(errorFlag2)
Add errorMessage2 to Messages[]
...
}
public boolean getErrorFlag1()
{
return errorFlag1;
}
public setErrorFlag1( ef1 )
{
this.errorFlag1 = ef1;
}
...
Could I use Map here? Is there a better way of "connecting" flag with a message?
Another solution (I hope i did not misunderstood your goal ):
enum ErrorMessage
{
ERROR_ONE("First message"), ERROR_TWO("Second message");
private String message;
ErrorMessage(String str)
{
message = msg;
}
public String getMessage()
{
return message;
}
}
This way you have constant error messages which contain a String as "message". Their type is ErrorMessage, and when you pass one like ErrorMessage.ERROR_ONE you can get their message by the getter method.
If you wish to have a class, which contains your errors, then you can create a collection of errors, and add or remove errors as they occured.
I'm not sure how your error messages are being set, but I would suggest storing an Integer representing each error in a List<Integer>. Errors would be added to the List through an addError method which allows manipulation of the encapsulated list.
Then place the definition of your error messages within a Map<Integer,String>, whose key corresponds with the appropriate error message. This will allow you to create new errors simply by adding a new entry in the map.
private List<Integer> errors = new ArrayList<Errors>();
private static Map<Integer> errorLookup = new HashMap<Integer,String>();
static{
errorLookup.put(1, "Error Message 1");
errorLookup.put(2, "Error Message 2");
}
public void addError(Integer errorKey){
errors.add(errorKey);
}
public List<String> getErrors(){
List<String> errorMsgs = new ArrayList<String>();
for(Integer key: errors){
errorMsgs.add(this.errorLookup.get(key).value);
}
return errorMsgs;
}
You can use a Map for sure,so that number of error messages are runtime determined. Use errormessage as key and boolean as value.
I'm getting some weirdness when I'm casting a Dynamic Proxy Class to the object I want it to be. At runtime, under certain conditions, I receive a ClassCastException.
In order to explain this better, here are the definitions for the classes/interfaces I want to use. Brackets have been put around any extended interfaces that (should be) irrelevant.
public interface CommandSender (extends Permissible)
public interface ConsoleCommandSender extends CommandSender, (Conversable)
public interface Player extends (HumanEntity, Conversable), CommandSender, (OfflinePlayer, PluginMessageRecipient)
Full Javadocs can be found here: http://jd.bukkit.org/apidocs/org/bukkit/command/CommandSender.html
Now, here is the code for my proxy class:
public class CommandSignsMessagingProxy implements InvocationHandler {
private Object sender;
private Object receiver;
private boolean silent;
public static Object newInstance(Object proxy) {
return newInstance(proxy, proxy, false);
}
public static Object newInstance(Object proxy, boolean silent) {
return newInstance(proxy, proxy, silent);
}
public static Object newInstance(Object sender, Object receiver) {
return newInstance(sender, receiver, false);
}
public static Object newInstance(Object sender, Object receiver, boolean silent) {
return Proxy.newProxyInstance(
sender.getClass().getClassLoader(),
sender.getClass().getInterfaces(),
new CommandSignsMessagingProxy(sender, receiver, silent));
}
private CommandSignsMessagingProxy(Object sender, Object receiver, boolean silent) {
this.sender = sender;
this.receiver = receiver;
this.silent = silent;
}
// Is called whenever a method is invoked
public Object invoke(Object p, Method m, Object[] args) throws Throwable {
Object result = null;
try {
String name = m.getName();
// If the receiver is being sent a message, only do so if the silent flag is not set
if (name == "sendMessage" || name == "sendRawMessage") {
if (!silent && receiver != null)
result = m.invoke(receiver, args);
} else {
result = m.invoke(sender, args);
}
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (Exception e) {
throw new RuntimeException("Unexpected invocation exception: " + e.getMessage());
}
return result;
}
}
And here is a fully working instance of the class:
Player proxy = (Player)CommandSignsMessagingProxy.newInstance(player, false);
proxy.sendMessage("Hi! Silent is turned off, so you can see this!");
proxy.setOp(true);
proxy.other_stuff();
Yet, this one doesn't work:
ConsoleCommandSender ccs = plugin.getServer().getConsoleSender();
CommandSender cs = (CommandSender)CommandSignsMessagingProxy.newInstance(ccs, false);
At run time, this example would produce the following:
java.lang.ClassCastException: $Proxy18 cannot be cast to org.bukkit.command.CommandSender
The created proxy class need to pass the interfaces it suppose to implement,
return Proxy.newProxyInstance(
sender.getClass().getClassLoader(),
sender.getClass().getInterfaces(),
new CommandSignsMessagingProxy(sender, receiver, silent));
failure seems to happen because CommandSender interface may not be returned from the call sender.getClass().getInterfaces() method. So try to see if it properly passes by debugging. If not try sending the interface manually to the method and see if it works.
I have the following db table:
id method_id
1 1
1 2
1 3
and 2 classes:
EmailController and Smscontroller
in my code, I need to iterate over the table and according to the method_id (1 or 2) to invoke the send method of either EmailController or Smscontroller.
What is the recommended design pattern for it?
EDITED
There could be 100 methods! I put only 3. This is why I do not prefer the if else.
As well, the object that I send to EmailController send method is different than the one that I send to SmsController send method.
In EmailController I need to send User object.
In SmsController I need to send Manager object
I can't think of a design pattern. But for ultimate flexibility you can have a design similar to this:
public interface Sendable /* or Sender, SendingManager, etc. */ {
public int getId();
public void send();
}
public class EmailController implements Sendable {
}
public class SmsController implements Sendable {
}
public class Sendables {
private Map<Integer, Sendable> sendables = new HashMap<Integer, Sendable>();
public void addSendable(Sendable s) {
this.sendables.put(s.getId(), s);
}
public void sendById(Integer id) {
this.sendables.get(id).send();
}
}
Then you can use it like this:
Sendables sendables = new Sendables();
sendables.add(new EmailController());
sendables.add(new SmsController());
sendables.add(new ChatController());
// etc.
Row row = table.getRow(...); // let's assume this gets a row from your table
sendables.send(row.getId());
Another solution could be to have an extra table like this:
TABLE: CLASS_NAMES
method_id class_name
1 "com.foo.SmsController"
2 "com.foo.EmailController"
And then pass class_name to Class.forName and let it instantiate the appropriate controller for you to use.
EDIT: A reflection-based version of the code as suggested by Luis. Note that for production use you should ensure that the passed parameters are valid (not null, etc.) and also handle exceptions with rigor.
TABLE: CLASS_NAMES
method_id class_name param_class_name
1 "com.foo.SmsController" "com.foo.Manager"
2 "com.foo.EmailController" "com.foo.User"
SendManager
public class SendManager {
private static final String SEND_METHOD_NAME = "send";
/* DAO for the CLASS_NAMES tables */
private ClassNameDAO classNameDao;
/**
* Gets the row corresponding to methodId, for example
* (1, "com.foo.SmsController", "com.foo.Manager") then using reflection
* instantiates an instance of SmsController and invokes its send method
* with <code>param</code> passed to it.
*/
public void send(int methodId, Object param) throws Exception {
ClassNameRow classNameRow = classNameDao.findByMethodId(methodId);
String senderParameterClassName = className.senderParameterClassName();
Class paramClass = Class.forName(senderParameterClassName);
if (!paramClass.isInstance(param)) {
throw new IllegalArgumentException("methodId and param are not compatible");
}
String senderClassName = classNameRow.getSenderClassName();
Class senderClass = Class.forName(senderClassName);
/* Your sender classes must be JavaBeans and have no-arg constructors */
Object sender = senderClass.newInstance();
Class paramClass = Class.forName(senderParameterClassName);
Method send = senderClass.getMethod(SEND_METHOD_NAME, paramClass);
send.invoke(sender, param);
}
}
Sample Usage
SendManager sendManager = new SendManager();
Manager m = ...;
sendManager.send(1, m);
User u = ...;
sendManager.send(2, u);
How about this:
abstract class Controller {
public static Controller getInstance(int methodId) {
switch (methodId) {
case 1:
return new EmailController();
case 2:
return new SmsController();
default:
return null;
}
}
public abstract void send();
}
class EmailController extends Controller {
#Override
public void send() {
System.out.println("sending email");
}
}
class SmsController extends Controller {
#Override
public void send() {
System.out.println("sending sms");
}
}
And use it like this:
Controller.getInstance(methodId).send();
I'm using the Strategy pattern and the Factory Method pattern in my solution.
Strategy Pattern
http://johnlindquist.com/2010/08/25/patterncraft-strategy-pattern/
http://en.wikipedia.org/wiki/Strategy_pattern