Saturday, June 29, 2013

JavaFX in Ignition

You're probably already familiar with the existence of JavaFX, Java's new UI rendering framework. Oracle is intending this to slowly replace Swing, and they've done a good job of creating something with a number of great features and a refreshed look and feel.

If you want to use JavaFX in Ignition, you may find yourself scratching your head. Currently, there is no JavaFX Canvas element built in to the Ignition platform, and libraries aren't importable in the Client or Designer. For the moment, JavaFX isn't "officially" supported by Inductive Automation.

However, if you're excited about JavaFX (like I am) and want to get your hands dirty anyway, Inductive Automation has added a little JavaFX support code and it is possible to get up and running in Ignition.


These are your steps to implement some JavaFX yourself:

1) Enable JavaFX in the client and designer
This can be done by editing your ignition.conf file in your Ignition/data directory. You'll want to add the line:
 wrapper.java.additional.XX=-Dignition.enablejfx=true

(where XX is the next number in sequence)

2) Write a module that provides a javafx.swing.embed.JFXPanel component.
(Javadocs Here)
This component would then be accessible to drop on an Ignition window and script through python to add elements to the scenegraph inside the javafx scene in the canvas. On your component, you'll want to set the "zoom-incompatible" property to true, so Ignition doesn't try to repaint / zoom in the designer. This is necessary, since JavaFX canvases have their own rendering thread and repaint methods that work differently than standard components.


Note that JavaFX is only installed by default on Java versions > 7u6. On early version of Java6, I believe the gateway.xml modification (which just adds a line to the .jnlp) has unpredictable consequences. (On the latest version of 6, it works fine, but just doesn't load JavaFX since JavaFX isn't installed by default with Java6.) The computers running the client will need JavaFX, or they won't be able to see the component. It's probably a good idea to test in the client whether the client's java supports JavaFX before trying to display a screen with JavaFX components on it (to keep any ClassNotFound Exceptions from rising). You may also be able to get creative and embed that logic into your component, so a lack of JavaFX would show a regular JLabel on the screen with "Could not render" information, or may simply change the component to gray or hidden.

Good luck! Feel free to post any successes back to the comments. I would love to hear what you're doing with all this.

Ignition: 7.5, 7.6

Wednesday, October 17, 2012

MongoDB, Part 2

So, I was able to get data from MongoDB collections pulled into datasets, and written back to datasets as well.  A little scripting was required.  I packaged it all up and attached it to this post.  Feel free to play around with it if you'd like.


There's 1 window and 1 script module to make this all work.  And, of course, make sure you grab the MongoDB module as well.

Project: MongoDB.proj

MongoDB Module: MongoDBDriver.modl


Note: There aren't any performance optimizations to this code.  Certainly, if you're thinking about using this in production, make sure to do a thorough code review and adjust it to act the way you need for your organization.


Ignition: 7.5 (7.5.3)

Friday, October 12, 2012

MongoDB in Ignition


I was recently asked whether Ignition supports NoSQL.  Well, NoSQL certainly isn't right for most things an Ignition system will be used for, but I thought I'd throw together a little proof-of-concept to show it could be done.

So, I present to you, MongoDB in Ignition!

It was really quite simple to make work (took 30 minutes).  Here's what I did:
1) Downloaded the MongoDB Java Driver from Mongo's website
2) Packaged it up as a module, telling it to load in all 3 contexts
3) Wrote a script based on http://www.mongodb.org/display/DOCS/Java+Tutorial

Here's my module.xml:
<?xml version="1.0" encoding="UTF-8"?>
<modules>
 <module>
  <id>MongoJavaDriver</id>
  <name>MongoDB Driver</name>
  <description>The MongoDB Java Driver.</description>
  <version>2.9.1.0</version>
  <requiredignitionversion>7.5.3.1163</requiredignitionversion>
  <requiredframeworkversion>4</requiredframeworkversion>
  <freemodule>true</freemodule>
  
  <!-- The MongoDB Java Driver libraries -->
  
  <jar scope="DCG">mongo-2.9.1.jar</jar>
  
 </module>
</modules>

After loading the module, you can simply use MongoDB from the Ignition Designer, Client, or Gateway.

Here's my testing script from my gateway:
from com.mongodb import Mongo

mongo = Mongo("localhost", 27017)
db = mongo.getDB("test")

testCollection = db.getCollection("test")
result = testCollection.findOne()
print result

Since I have MongoDB running on my system, the script above returned the first result found in the "test" collection, which was a:1.

Resulting Output:
{ "_id" : { "$oid" : "50787936a3513589171132bd"} , "a" : 1.0}

Simple as that. If you want a copy, follow the link below.

Download the module: MongoDBDriver.modl

Enjoy!


Note: Using the module this way gives you a straight connection to your MongoDB from the Ignition Gateway, Client, or Designer.  If you're running a script in the client or designer, it does *not* forward the information through the gateway. (This is different than Ignition database connections, which forward all traffic through the gateway.)

Ignition Version: 7.5 (7.5.3)

Monday, August 1, 2011

Exploration of 3d APIs In Java (As of August 2011)

I have always had an interest in the concept of 3d. In the past I've programmed simple environments in both OpenGL and Direct3d, and I even wrote a simple software 3d renderer in BASIC on a Tandy 102 years ago (family vacation growing up; way too many hours in that van). Recently, I've become interested in the idea of bringing 3d to my Java projects, so I've been exploring the options. Here's what I've found so far:


JavaFX

This is definitely the new kid on the block. JavaFX seems to think of itself as a superset of what Flash / Silverlight can do. You can code in pure java, and import your existing java business logic into JavaFX applications. It does run its own rendering, so you could see it as an alternative to Swing / AWT.

Although it's a potentially promising technology, the 3d support is very basic at this point, and not very practical. For example, primitives (such as cubes) are a feature they *may* add for the 2.0 release. (Richard Bair's June 4 reply here.) Plus, embedding it in Swing applications is more of a hack than an available feature, which makes integrating with an existing application a little difficult (and the way to do so may change with future releases).


Java 3D

This is the old mainstay which is used by a number of applications and toolkits. Java 3d has its own container, JCanvas3D, which makes it more difficult to integrate with existing swing component based layouts (though not impossible). It is a scene-graph based library. This means that you create java objects that contain 3d geometry and link them together; then Java 3d does the work to make the scene render. This is very different than a low level library, like OpenGL, where you control the rendering yourself.


JOGL

This is a community project called Java OpenGL, and is a Reference Implementation of JSR-231. (Look up information on the Java Community Process if you want more information on what this means.) This library lets you write code to control rendering in OpenGL. It is lightweight, unlike Java 3D, so it's easily embedded in existing swing windows in applications. Using this library, you're writing low level code, so it will take a lot more work than using Java 3D in order to get your scene rendering, but you do have a lot more control.


LWJGL

This is an alternative library to JOGL that provides most of the same features as JOGL, along with support for some other things like OpenAL(audio) and OpenCL(allowing use of GPU for CPU type tasks).

The advantages of JOGL and LWJGL (mainly the ability to embed in swing applications and the additional flexibility) make these the best option for me so far. The idea of using OpenGL programming is also exciting to me simply because I like the low level programming. However, I know it's not normally an efficient use of my time. Other people seem to agree, and have created a few libraries that use both JOGL and LWJGL as a base, but add scene-graph type abstraction to speed development.


Which brings me to...


jMonkeyEngine

This appears to be the main scene-graph library built on top of one of the low level libraries (LWJGL) that is in common use today. It has 9 years of development under its belt, and has even had a fork or two along the way. It seems to support most of the modern graphics abilities like bump mapping, shadows, parallax mapping and shader programming, etc, all in an easy-to-use quickly digestible form. For my purposes, this library may be a very solid choice.

Adding a jMonkeyEngine canvas to an existing Swing layout also seems to be as simple as adding a regular JComponent. Details are HERE if you're interested.

Special thanks to Erlend Sogge Heggen for corrections on the jMonkeyEngine information above.

----

I hope this serves as a good introduction to the 3D capabilities and libraries that you might use with Java. This is not a comprehensive list by any means, and I would encourage you to explore more on your own.


Now, a few fun links.

New jMonkeyEngine videos; Thanks Erlend
http://www.youtube.com/watch?v=WZ_alfF5Zt4
http://www.youtube.com/watch?v=8a0occCHl8Q

http://www.youtube.com/watch?v=5rxq_4brX_0 - Older jMonkeyEngine video, from JavaOne 2008

http://www.youtube.com/watch?v=8Dwyu3WKYDw - Ever seen bubblesort in 3d? JOGL

http://www.youtube.com/watch?v=BGnhpg2iaRo - Java 3d, simple house


Please feel free to leave comments if you have anything to add!

Wednesday, July 6, 2011

Adding Scripting Functions

So, you have a handy method available in one of your Java classes, and you wish you could use it in your jython script? Now you can!

The full list of items that are available from Python 2.5 are available here: http://docs.python.org/release/2.5/modindex.html

If we want to convert radians to degrees, let's say, there's no method in Python 2.5 to do it, but there is one in Java. And it couldn't be easier. java.lang.Math has a method called toDegrees(). Lets expose java.lang.Math straight to jython.

In your designer hook class, just add the following code:

 @Override
 public void initializeScriptManager(ScriptManager manager) {
  manager.addScriptModule("playground.math", java.lang.Math.class);
 }

Notice "java.lang.Math.class" in the last line. Giving the Class of an object will expose any static methods.

Now, open your designer, open up your script playground, and enter the following.

 import playground
 print playground.math.toRadians(.5)

And voila, we have full access!

If you want to expose any instance methods, just pass addScriptModule() an Object, and it takes care of the rest.

Of course, you can (and probably will) use your own classes and objects to create whatever scripting functions you need.

You'll want to run addScriptModule() in the client hook too, in order to have the same scripting functions available in both client and designer. If you need to run any of the scripting functions from a gateway script, be sure to add the lines to the gateway hook as well.

And that's it, easy as pie! (Maybe easier)

Note: As of Ignition 7.5.1, there's no way to "clean up" your scripting functions when your module is shut down. The Ignition developers have informed me that new methods (like manager.removeScriptModule(), for example) are planned to be added to Ignition in a future version.


Ignition Version: 7.5 (7.5.1)

Friday, June 10, 2011

Ignition Playground Project

As I've been writing Ignition Module code, I've found it useful to have a clean project to run some simple tests on so I can throw in code without affecting any of my live modules.

Here's my Playground project. Tested and running against Ignition 7.2, 7.3, 7.4, and 7.5 Module SDK.

I plan to keep this post updated as new versions are released.

Download it here: IgnitionModulePlaygroundv75.zip

Instructions:

1) Make sure you have the Module SDK.

2) Extract the files in the zip into your module workspace. (Default is "Module SDK 7.3.1\example". I copied that directory from the SDK to "C:\Development\Module SDK 7.3.1 Workspace\" on my system.)

3) Make sure the build-playground.xml and the module-playground.xml end up in the Build folder, alongside the Module SDK's build.xml.

4) In Eclipse, refresh your Build project, and import the three new projects. (Right click in the Package Explorer, go to "Import...", select General -> Existing Projects into Workspace, browse for the root directory, and click Finish.)

5) Note: From time to time, the requiredframeworkversion in the module.xml files need to be changed as new versions are released. Make sure your requiredframeworkverison matches that in the ModuleSDK's example module xml files. I try to keep the version in this download updated, so you may have to decrease the version number if you're using an old version of Ignition.

Enjoy!


Ignition Version: 7.2, 7.3, 7.4, 7.5

Thursday, May 26, 2011

Packaging an external library as a module

As I've been working with programming modules for Ignition, I've needed to use certain libraries along with my projects.

One way to do this: simply include the library's jars in your .modl file, and include them in your module.xml. This will make the library accessible for your module's classes' classloader.

What if the library is very large, though? This makes development take longer, since every module load requires reloading the entire library.

The solution I came up with was to package the library in its own module.

Steps
1) Grab the library's .jar files, and throw them in a directory.
2) Create a module.xml, like what I have below.
3) Package these in a .zip file, and change the extention to .modl

My library's module.xml:
<?xml version="1.0" encoding="UTF-8"?>
<modules>
 <module>
  <id>ApacheCXF</id>
  <name>Apache CXF</name>
  <description>The full Apache CXF 2.4.0 library and supporting libraries.</description>
  <version>2.4.0.1</version>
  <requiredignitionversion>7.2.5.76</requiredignitionversion>
  <requiredframeworkversion>2</requiredframeworkversion>
  <freemodule>true</freemodule>
  
  <!-- All the Apache CXF and CXF support libraries -->
  
  <jar scope="DG">antlr-2.7.7.jar</jar>
  <jar scope="DG">aopalliance-1.0.jar</jar>
  <jar scope="DG">asm-3.3.jar</jar>
                ...
 </module>
</modules>

Then, in your main module's module.xml, include this module as a dependency.

My main module.xml:
<?xml version="1.0" encoding="UTF-8"?>
<modules>
 <module>
  <id>myawesomemodule</id>
  <name>@NAME@</name>
  <description>@DESCRIPTION@</description>
  <version>@VERSION@</version>
  <requiredignitionversion>7.2.5.76</requiredignitionversion>
  <requiredframeworkversion>2</requiredframeworkversion>
  <freemodule>false</freemodule>

  <depends scope="G">ApacheCXF</depends>
  <depends scope="D">ApacheCXF</depends>

  ...

 </module>
</modules>

Note: A module can't have two dependencies. If your module already depends on fpmi, you'll need to move that dependency to the library module, and have your module just depend on the library module. So: "Your module" ->(depends)-> "Library module" ->(depends)->"fpmi"

Note 2: Your module will still load, even if it's missing dependencies. In your module's start up, make sure to check for the library's presence, and fault your module if it's not there.

Ignition Version: 7.2 (7.2.5)