From Optflux
Jump to: navigation, search

Pre-requisites[edit]

  • Working version of Eclipse IDE
  • Working installation of Subversion
  • If you wish to work directly with the latest version from the SVN server (OPTIONAL)

If you are behind a proxy, please note that some extra-configuration of subversion may be required:

  • You will need to edit the servers file and modify it accordingly
    • In Unix/BSD based systems (Linux, Mac OS X) you can usually find it under your home directory ~/.subversion/servers
    • In Windows systems it is usually in your user specific folder %APPDATA%\Subversion\servers
[global]
# http-proxy-exceptions = *.exception.com, www.internal-site.org
# http-proxy-host = defaultproxy.whatever.com
# http-proxy-port = 7000
# http-proxy-username = defaultusername
# http-proxy-password = defaultpassword
# http-compression = no
# No http-timeout, so just use the builtin default.
# No neon-debug-mask, so neon debugging is disabled.
# ssl-authority-files = /path/to/CAcert.pem;/path/to/CAcert2.pem
http-proxy-exceptions = *.example.com
http-proxy-host = proxy.example.com
http-proxy-port = 8080
http-proxy-username = myuserid
http-proxy-password = mypassword

Creating a new project for your plug-in (From release packages)[edit]

  1. Begin by Running Eclipse
  2. Having downloaded the release from the website, let's begin by creating a New Java Project
    Release1.png
  3. Give a name to your project and:
    1. select the Create project from existing source;
    2. select the path to the directory where you extracted the OptFlux release.
    3. press next;
    Release2.png
  4. Press the Create new source folder link
    1. Add a name to your plug-in, preferably under the plugins_src folder
    Release3.png
  5. Switch to the Libraries tab
    1. Press the Add JARs... button
    2. Add any jar library under the lib[your_architecture] folder. In the example we are adding some extra libraries for MacOS X (darwin64)
    Release4.png
  6. Your Eclipse workspace should look something like:
    Release4 1.png

Creating a Run Configuration to run OptFlux from within Eclipse[edit]

After creating a Project for your plug-in, you will need to create a Run Configuration in order to execute OptFlux from within Eclipse.

  1. Right-click your project;
  2. Access the Run As -> Run Configurations menu;
    Run config1.png
  3. Add a New Launch Configuration (top left icon);
  4. Fill in the fields as in the example
    Run config2.png
  5. Switch to the Arguments tab
    1. Add plugins_bin in the program arguments
    2. Add -Xmx1024m in the VM arguments (This is optional. It will increase your maximum Java heap space to 1GB. You can select any other value in the allowed range for your VM)
      Run config3.png
  6. Swich to the Environment tab
    1. You will need to create entries according to your system
      • Windows:
        • Variable: "LD_LIBRARY_PATH", value: libwin32
        • Variable: PATH, value: libwin32
      • Unix:
        • Variable: LD_LIBRARY_PATH, value: libunix32 or libunix64 depending on whether you are on 32 or 64 bit operating system
        • Variable: PATH, value: libunix32 or libunix64 depending on whether you are on 32 or 64 bit operating system
      • MacOS X:
        • Variable: DYLD_LIBRARY_PATH, value: libdarwin64
        • Variable: PATH, value: libdarwin64
      Run config4.png
  7. Click Apply and Run to see if OptFlux boots up normally

Configuring the structure of your plug-in directory[edit]

  1. Right-click the plug-in source folder (plugins_src/myplugin4optflux) and:
    1. Press Add -> New -> Package
      Release5.png
    2. Name it whatever you like. We like to use the same name for the first folder in the directory structure. In this case myplugin4optflux
      Release6.png
  2. Create the mandatory plugin.xml file:
  3. Right-click the plug-in source folder (plugins_src/myplugin4optflux) and:
    1. Press Add -> New -> File
      Release7.png
    2. Name it plugin.xml
      Release8.png
  4. To understand the structure and contents of the plugin.xml file, please refer to the The_Plugin.xml_File section.
    Release9.png
  5. Filling the sub-directory structure with rational packages is the next step. Since AIBench/OptFlux development is based on 3 main artifacts we usually sub-divide our java classes by those 3 artifacts.
    1. This means that we should create 3 sub-packages, one for the OPERATIONS, one for the VIEWS and one for our DATATYPES.
    2. Please note that this is optional. AIBench/OptFlux are agnostic to this, we just find it easier and more structured this way.
    3. You should get something like this
    Release10.png
  6. Finally, lets specify the compile directory for our plug-in source code. This is mandatory, since OptFlux will look for the compiled plug-in in a specified directory (plugins_bin by default)
    1. Access the properties window for your project
      Release11.png
    2. Access the build path entry on the list on the left;
    3. Switch to the source tab;
    4. Select the Allow output folders for source folders checkbox on the bottom and;
    5. Select the Output folder for your plug-in and click the Edit... button
      Release12.png
    6. Specify plugins_bin/myplugin4optflux as your compilation destination, click OK and we are done.
      Release13.png

What does it take to create a plug-in?[edit]

  1. Minimum: implement a class declared as an @Operation
  2. Create your own @Datatype (s)
  3. Create your own Views for the desired Datatypes
  4. Create your own GUIs for your Operations (Advanced - out of scope)

Create your first operation[edit]

Our first OptFlux operation is going to be something really simple. Say, we want our first basic operation to simply add two integers.

  • Create the MyOperation.java class inside the operations package
package myplugin4optflux.operations;

import es.uvigo.ei.aibench.core.operation.annotation.Direction;
import es.uvigo.ei.aibench.core.operation.annotation.Operation;
import es.uvigo.ei.aibench.core.operation.annotation.Port;

@Operation(description="My first OptFlux operation") //use the operation annotation so that OptFlux recognizes this class as an operation
public class MyOperation {
	
	int x, y;     // instance variables to keep my two integers
	
	@Port(name="x",direction=Direction.INPUT,order=1)   // use the port annotation with Direction = INPUT to note that this is an input of the operation
	public void setX(int x){
		this.x = x;
	}

	@Port(name="y",direction=Direction.INPUT,order=2)   // use the port annotation with Direction = INPUT to note that this is an input of the operation
	public void setY(int y){
		this.y = y;
	}
	
	@Port(direction=Direction.OUTPUT,order=3)                 // use the port annotation with Direction = OUTPUT to note that this is an output of the operation
	public int result(){
		return this.x + this.y;
	}
}
  • Now let's declare our new operation in the plug-in manifest, the plugin.xml file
    • We are extending the AIBench core with a new Operation, that means that we must connect to the operation-definition extension point and declare the new operation:
      Release14.png
    • Let's analyze the contents of this new entry:
      • <extension - declaration of the beginning of the new extension
        • uid="aibench.core" - This is the uid of the plug-in that contains the extension point
        • name="aibench.core.operation-definition" - The extension point to which we will connect
        • class="myplugin4optflux.operations.MyOperation"> - The path to the class that contains our operation
        • <operation-description - beginning the operation description
          • name="My Operation" - The name of the operation (this will be used in the OptFlux menus)
          • uid= "myplugin_myoperation" - The UID of our operation (this must be unique and will be useful in the future)
          • path="20@Plugins/1@MyOperations" - The path for our operation to be placed in the OptFlux menus (position@menu/position@submenu)
        • /> - close the operation description
      • </extension> - close the declaration of the new extension

Testing your first operation[edit]

  1. If everything went well you can execute OptFlux with the Run Configuration that we created before and you are ready to go
  2. You will be able to see your new operation on the menu:
    Release15.png
  3. By clicking it, you will lauch the operation. You can see that AIBench rendered a dialog GUI automatically for you. We will see how to create complex GUIs in the future.
    Release16.png
  4. Finally, executing the operation will place the result in the Clipboard. This is not the behavior that we expect in the future for OptFlux plug-ins, but we will get there.
    If you click the result object, the default view will be launched with the result
    Release17.png

CONGRATULATIONS :D - you just created your first OptFlux operation / plug-in (this one is simple though)

Creating your first Datatypes[edit]

If you are not already aware, AIBench/OptFlux is Datatype agnostic, that is, you can use whatever Datatypes you want to. However, if you want to improve the interaction of the user with the Datatypes, you can explicitly declare some properties of those same Datatypes.

For a more clear understanding of AIBench explicit Datatypes, please refer here

NOTE: All this datatypes will be created inside the datatypes sub-package.

Creating a Simple Datatype[edit]

Let's begin by creating a simple datatype to contain an integer (see this a simple wrapper)

public class MySimpleDatatype {
	
	private int number;
	
	public MySimpleDatatype(int num){
		this.number = num;
	}

	public int getNumber() {
		return number;
	}

	public void setNumber(int number) {
		this.number = number;
	}

}
  • You can see that the datatype does not declare a STRUCTURE, this happens because, by default, all types are interpreted as SIMPLE.
  • This would be the same as adding the annotation:
@Datatype(structure=Structure.SIMPLE)
public class MySimpleDatatype {
...
}

Creating a List Datatype[edit]

In this step we will create a List Datatype. This will be a wrapper to a List of MySimpleDatatype:

@Datatype(structure=Structure.LIST)
public class MyListDatatype {

	private List<MySimpleDatatype> myList;
	
	public MyListDatatype(List<MySimpleDatatype> list){
		this.myList = list;
	}

	@ListElements
	public List<MySimpleDatatype> getMyList() {
		return myList;
	}

	public void setMyList(List<MySimpleDatatype> myList) {
		this.myList = myList;
	}
	
}
  • Notice that:
    • We have the @Datatype(structure=Structure.LIST) annotation, declaring this as a List Datatype;
    • The method getMyList is annotated with @ListElements. This is mandatory for List datatypes, and tells AIBench how to access our list;

Creating a Complex Datatype[edit]

Now we will imagine a Complex Datatype that will contain a List of SimpleDatatype, an Operator (either SUM, SUBTRACTION, MULTIPLICATION or DIVISION) and another SimpleDatatype that will contain the result of applying the operator to the list of elements sequentially (this example is ignoring possible division by zero exceptions):

@Datatype(structure=Structure.COMPLEX)
public class MyComplexDatatype{
	
	private MyListDatatype list;
	private OperationEnumeration operation;
	private MySimpleDatatype result;
	
	public MyComplexDatatype(MyListDatatype list, OperationEnumeration operation,MySimpleDatatype result){
		this.list = list;
		this.operation = operation;
		this.result = result;
	}

	@Clipboard(name="Operation",order=1)
	public OperationEnumeration getOperation() {
		return operation;
	}
	
	@Clipboard(name="List of Elements",order=2)
	public MyListDatatype getList() {
		return list;
	}
	
	@Clipboard(name="Result",order=3)
	public MySimpleDatatype getResult() {
		return result;
	}
}
  • Notice that:
    • The class is annotated with @Datatype(structure=Structure.COMPLEX) annotation, declaring this as a Complex Datatype
    • The methods that give access to each of our class variables are annotated with @Clipboard(). This is mandatory.
      • The name property will be used as a name to display in the Clipboard.
      • The order property is the relative order by which each element will be displayed.

The OperationEnumeration was declared as follows:

public enum OperationEnumeration {

	SUM,
	SUBRACTION,
	MULTIPLICATION,
	DIVISION;
}

You should have your project looking like this:

Datatype1.png

Final Remarks Regarding datatypes[edit]

  • The @Datatype annotation contains several properties that can be specified. Please refer here for that.
  • You don't need to declare the Datatypes in the plugin.xml file. These will be captured automatically by AIBench/OptFlux when used in Operations or placed in the Clipboard.

Creating your first View[edit]

Let us create our first simple view for you to understand the basics.

Some initial remarks:

  • A view will have to be declared in the plugin.xml file;
  • A view is usually a simple Java class extending the JPanel class;
  • It is mandatory to have a unary constructor (with a unique argument), where that argument is an instance of the Datatype which the view will display.

We will create a view for our MySimpleDatatype, simply to display the value of the integer stored in each instance of this datatype:

public class MyViewForSimpleDatatype extends JPanel{
	
	private static final long serialVersionUID = 1L;
	
	MySimpleDatatype instanceToVisualize;
	
	public MyViewForSimpleDatatype(MySimpleDatatype toView){
		this.instanceToVisualize = toView;
		initGUI();
	}
	
	public void initGUI(){
		
		this.setLayout(new BorderLayout());
		
		JTextArea textArea = new JTextArea();		
		textArea.setText(Integer.toString(instanceToVisualize.getNumber()));
		textArea.setEditable(false);
		
		this.add(textArea,BorderLayout.CENTER);
		
		this.setVisible(true);
		
	}

}
  • Notice that:
    • This view is a simple JTextArea containing the value of the integer stored in each instance of the MySimpleDatatype class;
    • Notice the unary constructor public MyViewForSimpleDatatype(MySimpleDatatype toView);
    • The GUI initialization method (initGUI) should be called from the constructor. AIBench will invoke this constructor by default.

Declaring the view in the plugin.xml file[edit]

Declaring a view in the plugin.xml is a mandatory step. It is an easy process:

<extension 
    uid="aibench.workbench"
    name="aibench.workbench.view" >
    <view 
           name="SimpleDatatype View"
           datatype="myplugin4optflux.datatypes.MySimpleDatatype"
           class="myplugin4optflux.views.MyViewForSimpleDatatype"
    />		
</extension>

This entry should be added to the original plugin.xml file that should now look like this:

View1.png

Creating a more complex operation and gluing things together[edit]

Now we will create a more complex operation to interact with the recently created Datatypes and View:

We will name it MyMapOperation and place it inside the operations sub-package.

The code for the operation goes as follows:

@Operation(description="This operation creates a complex datatype containing an operator, a list and the result of applying the operator to each element of the list sequentially")
public class MyMapOperation {
	
	OperationEnumeration operation;
	int[] elements;
	
	@Port(name="Operation",direction=Direction.INPUT,order=1)          // deciding on the operator to use - INPUT
	public void setOperator(OperationEnumeration operation){
		this.operation = operation;
	}
	
	@Port(name="Elements",direction=Direction.INPUT,order=2)            // defining the list of elements on which to apply the operator - INPUT
	public void setList(int[] elements){
		this.elements = elements;
	}
	
	@Port(direction=Direction.OUTPUT,order=3)                                         // the output port
	public MyComplexDatatype getResult(){
		int res = elements[0];
		
		for(int i=1;i<elements.length;i++){
			if(operation.equals(OperationEnumeration.SUM))
				res += elements[i];
			else if(operation.equals(OperationEnumeration.SUBRACTION))
				res -= elements[i];
			else if(operation.equals(OperationEnumeration.MULTIPLICATION))
				res *= elements[i];
			else res /= elements[i];
		}
		
		List<MySimpleDatatype> listOfSimples = new ArrayList<MySimpleDatatype>();
		for(int elem: elements)
			listOfSimples.add(new MySimpleDatatype(elem));                     // create a list of MySimpleDatatype, one for each integer
		
		MyListDatatype list = new MyListDatatype(listOfSimples);               // create an instance of MyListDatatype. A wrapper for the list created above
		
		MySimpleDatatype result = new MySimpleDatatype(res);                 // create an instance of MySimpleDatatype to store the result
		
		MyComplexDatatype toReturn = new MyComplexDatatype(list, operation, result); // create an instance of MyComplexDatatype to hold all the the information above
		
		return toReturn;  // return the instance of MyComplexDatatype to the Clipboard
	}

}

The above example should be self-explanatory to any Java developer. We are applying the selected operation sequentially from the first element of the list to the next one, until the list of elements end.

Declaring the new operation in the plugin.xml file[edit]

We can not forget to declare the new operation in the plugin.xml file:

<extension
        uid="aibench.core"
        name="aibench.core.operation-definition"
        class="myplugin4optflux.operations.MyMapOperation">
        <operation-description
                  name="My Map Operation"
                  uid= "myplugin_mymapoperation"
                  path="20@Plugins/2@MyOperations"
         />
</extension>

If everything went well, we should now be able to run OptFlux using the previously defined Run Configuration and test our new Operation:

Testing the new operation[edit]

  • After running OptFlux, we should now be able to see a new operation in the menu:
    Complex1.png
  • The Input dialog for the new operation is generated and we will use it with the options depicted bellow:
    Complex2.png
  • We can now observe the Clipboard containing an instance of our MyComplexDatatype:
    Complex3.png
    • Notice the structure of the complex datatype being reflected in the Clipboard. The instance contains three levels at the root:
      • An Operation of the type: OperationEnumeration;
      • A List of Elements of the type: MyListDatatype;
        • The list of elements list all the instances of MySimpleDatatype therein contained;
      • A Result of the type: MySimpleDatatype;
    • This structure perfectly reflects the one that we defined in the Java code. This structure can be as complex as the programmer wishes.
  • Finally by pressing one of the instances of MySimpleDatatype in the Clipboard, the new View will be launched in the right panel. You can see that the default view is also there. The programmer can add as many different views as desired to a given Datatype
    Complex4.png