Who’s On Phirst

Official blog of Phurnace Software.


Posted by: Alexander Bibighaus on

Ant, the de-facto standard build tool for Java, could be defined as a platform independent scripting tool similar to Make but with an XML syntax. Ant is mature, extensible, and relatively easy to use. These qualities paved the path for Ant to be applied to other problems besides "building software". For instance, Ant is commonly used as a scripting tool to move files around, and moreover as a test tool to launch tests and generate reports. Most Java developers already know everything I just said.

I would like to share with you another way Ant can add value to your organization, embedded Ant. It is often the case where your software needs to do tasks similar to those available in Ant. For a long while, this was a cool thought, but not a good solution in practice. It required either launching Ant in another process or studying the Ant source code so you can work through some significant issues.

However, improvements in 1.6 and 1.7 now allow Ant to be easily embedded. I first successfully embedded Ant about six months ago with version 1.6. I considered the following points before making the decision to give it a try.

  • Ant is very mature.
  • The wide usage of Ant implies a well tested infrastructure
  • Ant tasks are cross platform
  • High probability anyone who inherits this code will know Ant

My product requirements for this feature were that it:

  • Must be able to fork a Java JRE on multiple OS's and run a process to completion (Windows, AIX, Linux).
  • Must be able to kill or stop the process on-demand.
  • Must be able to capture the standard output and standard error in real time.

Sure, I could use the Java IO and Runtime; however, when weighing the cost to write, debug, and test this code versus taking the time to figure out how to embed Ant, the decision was easy.

Here is a quick tutorial that demonstrates the concept. In practice, I use more code to make this easier. However, this shows the concept.

  • Create your build.xml and package it in jar.





Hello ${to}


     

  • Create an Ant Wrapper

Project project = new Project();

project.init();

project.setBasedir(workingDir);

DefaultLogger antLogger = new DefaultLogger();
antLogger.setErrorPrintStream(System.err);
antLogger.setOutputPrintStream(System.out);
antLogger.setMessageOutputLevel(Project.MSG_INFO);

project.addBuildListener(antLogger);

// Load the build file
InputStream is = MyClass.getResourceAsStream(“build.xml”);
File tempFile = File.createTempFile();
copy(is, tempFile);

ProjectHelper.getProjectHelper().
parse(project, buildFile);

// set properties
project.setProperty("to", "World");

project.executeTarget("sayHello");

A few caveats still remain:

  • The project.init() is expensive. If possible, you only want to do this once per build file.
  • The ProjectHelper.getProjectHelper() method does not yet take an InputStream as an argument. The source code appears to allow you to write a plugin that would support this, but I took a simple approach. I read the resource from the jar and copy it to a temp file.

In summary, Ant has proved useful as an embedded library. However, what I noticed most was that Ant not only provided a robust solution, but also enabled other features that would have otherwise not been considered.

In Embedded AntAnt
Comment (0) Read More...


Posted by: jgass on

AUSTIN, Texas — July 21, 2008 — Phurnace Software, Inc., the Java application deployment company, today announced that it has completed its $5 million Series A financing, led by S3 Ventures, a Texas-based venture capital firm. Previous investors, including DFJ Mercury, also participated in the financing. The capital will be used by Phurnace to expand sales, marketing and development activities for its patent-pending deployment automation products.

The company provides IT operations staff with data center automation tools to dramatically reduce application deployment times, decrease configuration errors, lower costs and enable more efficient enterprise Java deployments. The company’s flagship product, Phurnace Deliver™, is used by some of the country’s largest companies in multiple vertical markets. It supports deployments and automated configurations on the leading web application server platforms, including IBM WebSphere®, BEA WebLogic® and RedHat JBoss™. The company has also recently announced automated deployment support for IBM WebSphere® Portal.

“S3 invests in companies with innovative technology, a compelling measurable value proposition and significant customer traction,” said Brian R. Smith, Managing Director at S3 Ventures. He continued, “Phurnace’s products address a clear need in the marketplace, as evidenced by its use among Fortune 500 companies, and we are looking forward to helping them expand their rapidly growing business.”

“The fit was strong between Phurnace and S3 Ventures because we both see how data center automation is top-of-mind in enterprise IT departments. S3 sees the large investment opportunity in the data center and Phurnace has created a powerful solution to reduce headaches and costs there,” stated Larry Warnock, President and CEO of Phurnace Software. He continued, “Companies continue to invest inordinate amounts of time and effort into scripts and manual processes where automation is a much better approach. The value of using Phurnace Deliver™ can be seen immediately after its installation.”

System administrators and Java developers use Phurnace’s technology to reduce errors, save time and eliminate the need for hard-to-maintain scripting while configuring web application servers. The use of Phurnace software results in a significantly more efficient deployment process which can be shortened from weeks to minutes. The agent-less architecture of Phurnace Deliver™ fits into companies’ existing data center processes and the command line interface (CLI) option allows for direct integration to software build and operation toolsets such as HP Server Automation®, IBM Rational®, IBM Tivoli® and BMC BladeLogic™.

About Phurnace Software, Inc. Phurnace creates software that troubleshoots configuration problems and accelerates deployments of Java EE applications. It eliminates the error-prone, repetitive processes and headaches associated with troubleshooting, configuring and migrating of software running on web application servers -- regardless of vendor or version. System administrators and developers use Phurnace to eliminate errors, save time and reduce overall deployment costs. www.phurnace.com.

About S3 Ventures S3 Ventures is an early-stage venture capital firm investing in companies which address large market opportunities in the information technology and medical device sectors. We invest primarily around the Southwest with a focus on Texas. Our offices are located in Austin and Houston. S3’s team is a group of seasoned investors and successful entrepreneurs who have repeatedly built companies into great returns for investors. At S3 today, we help talented entrepreneurs take their technology and market knowledge and form valuable businesses in a methodical fashion. For more information about S3, visit http://www.s3vc.com/.

Phurnace and the Phurnace flame logo are trademarks or registered trademarks of Phurnace Software, Inc. in the United States and other countries. All other names are the trademarks or registered trademarks of their respective companies.

###

In phurnace
Comment (0) Read More...


Posted by: Pete Pickerill on

As you may, but probably don't know, Phurnace got some Phunding. The management team put in countless hours over the last several months and the process was apparently fraught with twists and turns that would give Gordias pause. Thankfully, our fearless leaders didn't share with us each and every bump in the road. Even more thankfully they didn't share with us those moments, of which I'm sure there were a few, when the road disappeared altogether. I'm a lot like Bill Paxton's character in 'Aliens': I talk a good game and will bust my butt until the bitter end, but am real quick to loudly proclaim "Game Over, man!" when things don't go as planned. Knowing too much would give me fits.

When it comes to spending someone else's money, I think a lot of software companies screw up by making financial choices like the Lohans' make parenting decisions. Instead of worrying about their employee's productivity and professional growth, they want their employees to think their job is cool. Instead of laying the groundwork for long term success, they try to compete with the outrageous perks offered by companies like Google. Don't get me wrong. Fully stocked break rooms, expensive chairs, and ping pong tables are nice. And even though I'm as pale as they come and have a history of skin cancer, I love a good beer bash on a party barge just as much as the next guy. But I would not trade quality hardware or capable new co-workers for any of these fleeting perks. Good employees don't join a company for the parties or bottomless soft drinks. They join a company because they believe in it's products, are optimistic about the company's success, or are intrigued by the professional growth it offers them. The ones that get caught up in the perks are usually the first ones to leave when something new comes along or complain when the company hits leaner times and has to cut back on the cool stuff so they can make payroll.

The culture here is based on honesty and openness. So while the nitty-gritty of start-up funding wasn't revealed to us there has been a lot of discussion of the funding process. The chickens were never counted before they hatched, but we sure did make a lot of plans for exactly how we were going to count those chickens and what we were going to buy with our new found...poultry. O.K. I think I've lost control of the hatching chicken metaphor. Anyway, during these discussions on what was to be done with the funding it became clear to me how much different Phurnace is than some of the other start-ups I've worked at. The coolest thing about this company is that everyone here seems to be in agreement with the long-term plan. By opening up discussion of business decisions to all of us, it's easier for us to see, appreciate, and contribute to the company's growth and success. It's also striking that everyone can now rest assured that a dime is not spent without tracing it back to a concrete benefit for the company. We are making quality hires and investing in an infrastructure that will optimize productivity and yield solid deployment solutions that we can not only sell, but also take pride in. And isn't building something new and cool what working at a startup is all about?

In phurnace
Comment (0) Read More...


Posted by: Wesley Willard on

To a non-geek, spending a weekend in hotel conference rooms listening to presentations on the latest technologies in software development might make them beg, "just shoot me now, please". But to someone interested in keeping abreast of these sorts of things, for both company and personal reasons, it was a very nice way to do just that. Plus, it was hot as hell outside, the neighborhood pool is even hot, and the lake is just too far away.

The Lone Star Symposium was held this past weekend here in Austin, and it was a great show. The lack of vendor presence at these conferences allow software developers to focus on the technology itself. The people who put this conference together go out of their way to provide all the amenities to the attendees, such as good food, snacks, not to mention some of the best industry experts out there. With regard to the experts, I am always pleased to find not only those who write about the technologies at this show, but also those who have had a hand in developing them. A case in point, the presenter for the Spring Framework was Keith Donald, one of principals and founders.

It's always a shame that you can't make it to all the sessions in this type of conference, but you generally can't go wrong with any selection. Just to sort of sum up, the hottest topics this year were the ones concerning dynamic languages, such as Groovy, and it's related framework, Grails. Also, Spring continues to be THE overarching framework for J2EE development.

My favorite session, though, was one by Neil Ford, titled "Productive Programmer: Acceleration & Automation". I am a sucker for cool command line tools, and he talked about such great productivity enhancers such as Auto-Hot Key, which allows you to define (and redefine) hot keys in Windows, and clcl, which allows you to maintain multiple clipboards. I am very keyboard-oriented, and these tools will allow me to stay away from my carpal-inducing mouse.

Next time one of these conferences makes its way near you, check it out. Especially if its a hot summer weekend!

In Spring FrameworkGroovy
Comment (0) Read More...


Posted by: Alexander Bibighaus on

Recently, I was entertained by hearing complaints from a friend regarding their Agile practice and how impractical and inefficient it seemed. This conversation led me to think about our own agile practices at Phurnace and other companies for which I’ve worked. It is my experience, since the Agile boom, companies tend to adopt a hybrid approach that is typically a collection of agile practices mashed up with traditional practices from which people feel comfortable. I reviewed some of the basic principles of Agile software development and found several common pitfalls.

Individuals and interactions over processes and tools

Agile projects are geared to expect change. Agile practices expect that management, sales, and product leadership frequently change project requirements. Recognizing this as a reality rather than denying it leads to a more honest and accurate approach for your organization. Thus, agile projects must explicitly abandon traditional planning in favor of direct interaction with individuals. With a clear focus on high value features and releasing valuable software often, a software team can adapt to frequent changes yet consistently deliver additional product "value”.

Traditional team management use tools such as Microsoft Project to breakdown work items that look into the project's future. Resources are allocated, dependencies are tracked, and tasks are mapped to individuals. This plan is traditionally managed by identifying the "critical path" for final delivery. Any change or diversion from the plan forces the plan to be re-worked. If the project has little variance, this approach is effective. However, most software projects change often resulting in making the project plan irrelevant.

One pitfall is that most hybrid approaches continue to use traditional tools to chart out a project plan which only confuses the leadership. These estimates are put into a Microsoft Project chart to determine which stories are feasible for the next iteration. This piece of planning, even on a smaller scale, is often out of touch with reality. The reason lies behind the estimates. A spreadsheet or Gant chart of numbers fails to communicate many of the inferences and risks that would otherwise be learned by direct interaction with the team members or the lead. In essence, given a 3-4 week timeframe, relying on your team's depth of knowledge and experience thru personal interaction is a better measure for the feasibility of tasks.

The second pitfall with this theorem is around processes. Adding unnecessary processes under the name of “Agile” is, in my experience, the most abused part of the practice. For instance, daily or frequent standup meetings are very effective for encouraging frequent collaboration and communication between your team members. However, if the traditional “weekly development meeting” is simply expanded to a “daily development meeting”, it only achieves 5 times more wasted time.

Working software over comprehensive documentation

The most important thing in a software organization is consistently creating software that provides value. Frequent collaboration with your collegagues often replaces the need for short-lived documentation. Rarely, does an internal design document or test plan add value to a product suite; while actual development or test execution can produce another valuable release.

The pitfall often found in a hybrid approach is not usually around typical documentation such as test plans for design documents. Instead, organizations adopt traditional practices such as weekly status reports and require so-called-Agile “daily” status reports. Daily status reports are just another form of comprehensive documentation leaving less time for working on software!

I am sure many people experience issues with Agile development while also seeing huge improvements over the traditional practices. I am very interested in hearing any feedback or opinions. In a follow-up blog, I plan to address the other two theorems:

Customer collaboration over contract negotiation
Responding to change
over following the plan

In Agile Software Development
Comment (0) Read More...


Posted by: Shawn Spiars on

From time to time I visit the Eclipse news groups to find a solution to a problem I am having with a particular area of Eclipse. Since Eclipse is such a huge platform with many projects there are many different news groups, each designed to cover a particular project or API (Application Programming Interface).

Some of my favorite Eclipse news groups are:

eclipse.platform
eclipse.platform.rcp
eclipse.platform.swt

Often while I am looking for answers in a news group I run across questions that I have already conquered and so I try to give back and help others. Recently I responded to a question about how to perform in-line editing within the cell of an SWT (Standard Widget Toolkit) table. I have included my example java program below. If you are a Java developer and somewhat familiar with SWT/JFace then you should have no problems understanding the example code. If you are new to SWT/JFace I have provided a brief summary of the primary components used to create the example.

Looking at the java code below you will see that the program contains a main method to launch the java program. The primary UI component is an SWT Table which is added to an SWT Composite. Under the table I have added SWT buttons to “Add” and “Remove” rows from the table. The SelectionListeners on the buttons handle the add and remove actions. The model for the table is a POJO (Plain Old Java Object) which I have named “Row”. A TableContentProvider and TableLabelProvider provide the content and labels for the table and the TextCellEditor provides the ability to edit the table allowing a user to type data directly into the table’s cells.


import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;

/**
* This is an example program showing how to use a TableCellEditor
* to allow direct editing of a table's cell.
*
* @author Shawn Spiars
*
*/

public class TableCellModifierExample {

private Table table;
private TableViewer tableViewer;

private final static String[] COLUMN_HEADINGS = {"Property",
"Value"}
;

public static void main(String [] args) {
new TableCellModifierExample();
}

public TableCellModifierExample() {
Display display = new Display();
Shell shell = new Shell(display, SWT.SHELL_TRIM);
shell.setText("TableCellModifier Example");
shell.setLayout(new FillLayout());

createContents(shell);

shell.setSize(400, 400);
shell.open();

while (!shell.isDisposed()) {
if (!display.readAndDispatch()) display.sleep();
}
display.dispose();
}

protected Control createContents(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout(1, false);
layout.verticalSpacing = 10;
composite.setLayout(layout);
GridData data = new GridData(GridData.FILL_BOTH);
data.grabExcessHorizontalSpace = true;
composite.setLayoutData(data);

table = new Table(composite, SWT.BORDER | SWT.V_SCROLL
| SWT.MULTI | SWT.FULL_SELECTION);
table.setLinesVisible(true);
table.setHeaderVisible(true);
data = new GridData(SWT.FILL, SWT.FILL, true, false);
data.heightHint = 300;
table.setLayoutData(data);

TableLayout tableLayout = new TableLayout();
table.setLayout(tableLayout);

tableLayout.addColumnData(new ColumnWeightData(10, 100,
true));
TableColumn column = new TableColumn(table, SWT.NONE);
column.setText(COLUMN_HEADINGS[0]);
column.setAlignment(SWT.LEFT);

tableLayout.addColumnData(new ColumnWeightData(15, 200,
true));
column = new TableColumn(table, SWT.NONE);
column.setText(COLUMN_HEADINGS[1]);
column.setAlignment(SWT.LEFT);

tableViewer = new TableViewer(table);
tableViewer.setColumnProperties(COLUMN_HEADINGS);
tableViewer.setContentProvider(new
TableContentProvider());
tableViewer.setLabelProvider(new TableLabelProvider());

CellEditor[] editors = new CellEditor[2];
editors[0] = new TextCellEditor(table);
editors[1] = new TextCellEditor(table);
tableViewer.setCellEditors(editors);
tableViewer.setCellModifier(new TableCellModifier());

Composite buttonComposite = new Composite(composite,
SWT.NONE);
FillLayout fillLayout = new FillLayout(SWT.HORIZONTAL);
fillLayout.spacing = 10;
buttonComposite.setLayout(fillLayout);

Button addButton = new Button(buttonComposite,
SWT.PUSH);
addButton.setText("Add");
addButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
Row row = new Row("", "");
tableViewer.add(row);
table.setTopIndex(table.getItemCount());
table.select(table.getItemCount()-1);
tableViewer.editElement(row, 0);
}
});

Button removeButton = new Button(buttonComposite,
SWT.PUSH);
removeButton.setText("Remove");
removeButton.addSelectionListener(new
SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
ISelection selection =
tableViewer.getSelection();
if (selection instanceof
IStructuredSelection) {
Iterator iterator =
((IStructuredSelection)selection).iterator();
while(iterator.hasNext()) {
Object obj = iterator.next();
tableViewer.remove(obj);
}
}
}
});

return composite;
}

public class TableLabelProvider extends LabelProvider
implements
ITableLabelProvider {
public Image getColumnImage(Object element, int
columnIndex) {
return null;
}

public String getColumnText(Object element,
int columnIndex) {
Row row = (Row) element;

switch
(columnIndex) {
case 0:
return row.getKey();
case 1:
return row.getValue();
}

return null;
}

}

public class TableContentProvider implements
IStructuredContentProvider {
public Object[] getElements(Object parent) {
List results = new ArrayList();
if (parent instanceof ArrayList) {
results = (ArrayList) parent;
}
return results.toArray();
}

public void dispose() {
}

public void inputChanged(Viewer viewer, Object oldInput,
Object newInput) {
}

}

class TableCellModifier implements ICellModifier {

public boolean canModify(Object element,
String property) {
return true;
}

public Object getValue(Object element,
String property) {
Object result = null;

Row row = (Row) element;

List list = Arrays.asList(COLUMN_HEADINGS);
int columnIndex = list.indexOf(property);

switch (columnIndex) {
case 0:
result = row.getKey();
break;
case 1:
result = row.getValue();
break;
}

return result;
}

public void modify(Object element, String property,
Object value) {
List list = Arrays.asList(COLUMN_HEADINGS);
int columnIndex = list.indexOf(property);

TableItem tableItem = (TableItem) element;
Row row = (Row) tableItem.getData();

switch (columnIndex) {
case 0:
String key = (String) value;
if (key.length() > 0) {
row.setKey(key);
}
break;

case 1:
String v = (String) value;
if (v.length() > 0) {
row.setValue(v);
}
break;
}
tableViewer.update(row, null);
}

}

private class Row {
private String key;
private String value;

public Row(String key, String value) {
setKey(key);
setValue(value);
}

public void setKey(String key) {
this.key = key
}

public String getKey() {
return key;
}

public void setValue(String value) {
this.value = value;
}

public String getValue() {
return value;
}
}

}

In SWTJFaceSWTStandard Widget ToolkitEclipse
Comment (0) Read More...


Posted by: Pete Pickerill on

Even though it’s been available for a few months, I only recently had time to check out the latest and greatest free virtualization offering from VMWare. I haven’t run it through the wringer completely, but from what I’ve seen there are several new features and improvements that will definitely hasten the upgrade process in our test environment once it clears Beta. Here’s what I like so far:

  • A vastly better web console. The console obviously came under some major scrutiny. The 1.0 version wasn’t unusable, but it wasn’t as feature rich and intuitive as the 2.0 console. Everything you need to manage your virtual machines is easily accessible in a clean web app.
  • More detailed event reporting. This helps you keep track of changes made to your virtual machines. It also helps you find who started, stopped, or reverted your virtual machines. So now instead of cursing the Void when a VM is reverted out from under you and you lose weeks of unsaved test data, you can find the culprit and break their coffee cup or mess with their chair settings late at night when no one else is around.
  • If you are not a late night saboteur and would rather avoid the situation altogether, virtual machine permissions are a lot easier to manage in this release.
  • Instead of assigning a single ‘Default Virtual Machine Location’ as you do in 1.0, you organize your virtual machines in one or more datastores. You can then set access permissions on your datastore to keep others from interfering with your diabolical machinations…or software development.
  • Virtual Machine memory allocation ceiling has more than doubled. 1.0 capped per virtual machine memory allocation at less than 4 GB. 2.0 bumps this up to 8 GB as long as you have the memory to spare. This is a very big deal for anyone that plans on running multiple virtual machines hosting WebSphere Portal.
  • Updates to the VIX API. 2.0 includes support for an updated API (VIX 1.5) with some exciting new features. I am most anxious to get my hands on the Record and Playback features.

The only thing that I hoped was going to be available in 2.0 was support for multiple snapshots per virtual machine. This would make it a lot easier to switch between WebSphere and WebLogic patch levels when tracking down configuration bugs. All in all, I’m very pleased and excited about digging deeper.

In Vmware Server 2.0Virtualization
Comment (0) Read More...


Posted by: Daniel Nelson on

I spent most of last week in hotter-than-the-sun Las Vegas at the HP Software Universe trade show. Here are some quick observations:
 

  1. Hewlett Packard Software is all about the data center. Really. All they talk about is making data centers run more efficiently – from test to deployment to performance metrics. Up and down the stack. It was nice to see such a big company have such a singular focus. There is no confusion in the HP ranks as to what their goal is.
  2. As for web application servers that attendees used, WebLogic, WebSphere and Jboss were all about equally represented. Only one attendee we talked to was on Oracle OAS. Also, very few of the WebLogic prospects we talked to were on release 9.2 or 10. Most of them were on 8.1. I would have thought more companies would have migrated up by now.
  3. The HP staff was pretty awesome. Lots of engineers from HP roaming around and looking at what new technology their partners had to offer. We must have talked to 8 different engineers from the Opsware group alone that wanted to learn more about what we do – and they were just as forthcoming in helping us with the questions we had about OpsWare. (Disclosure: Phurnace is coming out with an integration to Server Automation soon – that’s one of the reasons that we were at the show).
  4. Finally, the Palazzo and Venetian are pretty swank.

In Server AutomationOpswareHP
Comment (0) Read More...


Posted by: Wesley Willard on

The Spring Framework has become the most popular open source application framework in the Java space in recent years. One of its most powerful features is its ability to allow developers to create Spring Beans, which can be configured together to create an application's object graph, or data structure. The framework provides a consistent interface to accessing these beans which avoids unnecessary dependencies between components.

JMX (Java Management Extensions) is a technology that enables the configuration, instrumentation, and monitoring of Java applications of all sorts, both J2SE and J2EE. It has gained wide-spread acceptance in the Java community as the standard API for these tasks. JMX provides access to MBeans (JMX's version of Spring's Beans), which compose its management interface. This is handled through a software layer known as the MBeanServer.

One useful piece of the Spring Framework is its direct support for JMX. Spring provides the ability to register its Beans in an MBeanServer, which can then be interrogated and modified by management applications by Spring Bean interface methods. The interface to Spring Beans is more intuitive and easier to use than the MBean interface, and abstracts many complicated details.

The follow example shows how Spring JMX can be used to provide remote management capability of its Beans. It will illustrate both server and client configuration and code. It will assume some Spring and JMX knowledge.

First, I create the Spring server-side application context configuration:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" 
 "http://www.springframework.org/dtd/spring-beans.dtd"> 
 
<beans>
    <bean id="registry" class=
"org.springframework.remoting.rmi.RmiRegistryFactoryBean">
        <property name="port" value="1090"/>
    </bean>
    
    <bean id="exporter" 
class="org.springframework.jmx.export.MBeanExporter" 
lazy-init="false"
         <property name="beans">
             <map>
                 <entry key="spring:name=jmxBean">
                     <ref local="jmxBean"/>
                 </entry>
             </map>
         </property>
         <property name="assembler" ref="assembler" />
         <property name="server">
             <ref local="mbeanServer"/>
         </property>
    </bean>
 
    <bean id="mbeanServer" 
        class="org.springframework.jmx.support.
MBeanServerFactoryBean"/> <bean id="jmxBean" class="com.phurnace.JmxBeanImpl"> <property name="name"> <value>Daffy Duck</value> </property> <property name="rating"> <value>5</value> </property> </bean> <bean id="jmxAttributeSource" class="org.springframework.jmx.export.annotation.
AnnotationJmxAttributeSource"/> <bean id="assembler" class="org.springframework.jmx.
export.assembler.MetadataMBeanInfoAssembler"> <property name="attributeSource" ref="jmxAttributeSource"/> </bean> <bean id="serverConnector" class="org.springframework.jmx.support.
ConnectorServerFactoryBean"> <property name="objectName" value="connector:name=rmi"/> <property name="serviceUrl" value="service:jmx:rmi://localhost/jndi/rmi://localhost:
1090/myconnector"/> </bean> </beans>

The MBeanExporter class is used to specify the Spring Beans that are to be exposed via JMX by the MBeanServer. The MBeanServer is implemented by the Spring MBeanServerFactoryBean class. In this example, it will expose the specifed Beans via RMI. If there is an existing MBeanServer, such as in a web container like Tomcat or JBoss, Spring JMX will use that one. Spring also allows for the specification of an RMI registry for the MBeanServer. It will be started when the application context file is loaded.

The AnnotationJmxAttributeSource and MetadataMBeanInfoAssembler classes are used allow Java 5 Annotations to indicate which classes and methods which will be exposed in the MBeanServer.

The final bean in the configuration file configures a ConnectorServerFactoryBean to provide remote access to the Spring Beans. This connector will be running over RMI, on port 1090.

Now, I configure the Spring Bean (jmxBean), which looks a whole lot like a standard Java Bean:


//
// Interface class
//
package com.phurnace;

public interface JmxBean {
    public String getName();
    public void setName(String name);
    public int getRating();
    public void setRating(int rating);
}



//
// Implementation of JmxBean interface
//
package com.phurnace;

import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedResource;

@ManagedResource(objectName=
"spring:name=jmxBean", description="Managed Bean")
public class JmxBeanImpl implements JmxBean {
    private String name;
    private int rating;

	
    @ManagedAttribute(defaultValue="animal")
	public String getName() {
		return name;
	}
     
    @ManagedAttribute
       (description="Name Attribute",
        defaultValue="animal")
	public void setName(String name) {
		this.name = name;
		System.out.println("Setting name to " + this.name);
	}

	@ManagedAttribute
	    (description="Rating Attribute")
	public int getRating() {
		return rating;
	}

	public void setRating(int rating) {
		this.rating = rating;
	}
}

As I indicated before, Spring allows usage of Java 5 Annotations to specify which classes and methods will be loaded into the MBeanServer, as well as metadata about them. Annotations are straight-forward to use, and provide great visibility to the developer as to which methods are exposed.

Finally, here is an example server, which loads up the Spring application context file.


package com.phurnace;

import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.
ClassPathXmlApplicationContext; public class SpringJmxServer { private static Logger logger =
Logger.getLogger(SpringJmxServer.class); /** * @param args */ public static void main(String[] args) { org.apache.log4j.BasicConfigurator.configure(); ApplicationContext ctx = new
ClassPathXmlApplicationContext("/com/phurnace/server-jsr160.xml"); if (ctx != null) { logger.info
("Successfully loaded ApplicationContext"); } JmxBean jmxBean = (JmxBean) ctx.getBean("jmxBean"); String name = jmxBean.getName(); logger.info("Name is " + name); while ( !name.toUpperCase().equals("EXIT") ) { try { Thread.sleep(5000); name = jmxBean.getName(); } catch (Exception e) { logger.error("Trapped error " +
e.getMessage()); System.exit(1); } } System.exit(0); } }

Now, on to the client-side of things. First, I will show how to access the Spring Bean as a standard JMX client:


package com.phurnace;

import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

import org.apache.log4j.Logger;

public class TestJmxClient {
	private static Logger logger = Logger.getLogger(
TestJmxClient.class); private final String objectNameStr = "spring:name=jmxBean"; private final String jmxRmiStr = "service:jmx:rmi://localhost/jndi/rmi://localhost:1090/
myconnector"; private ObjectName objectName; private JMXServiceURL jmxUrl; private JMXConnector jmxConnector; private MBeanServerConnection mbsc; /** * @param args */ public static void main(String[] args) { org.apache.log4j.BasicConfigurator.configure(); if (args.length == 0) { logger.info("Usage: java com.phurnace.
TestJmxClient "); System.exit(0); } TestJmxClient jmxClient = new TestJmxClient(); jmxClient.init(); jmxClient.accessBean(args[0]); System.exit(0); } public void init() { try { objectName = new ObjectName(objectNameStr); jmxUrl = new JMXServiceURL(jmxRmiStr); jmxConnector = JMXConnectorFactory.connect
(jmxUrl); mbsc = jmxConnector.getMBeanServerConnection(); } catch (Exception e) { logger.error("Error initializing
connection"); } } public void accessBean(String newName) { String name = getName(); if (name == null) { return; } logger.info("Original name is " + name); logger.info("Setting new name to " + newName); setName(newName); // // Access the name again to check it's value // name = getName(); if (name == null) { return; } logger.info("New name is " + name); } private void setName(final String name) { final String operationName = "setName"; try { Object[] params = new Object[1]; params[0] = name; String[] signature = new String[1]; signature[0] = new String("java.lang.String"); mbsc.invoke(objectName, operationName, params, // no parameter signature ); } catch (Exception e) { logger.info( "Error setting name value in bean "
+ e.getMessage()); } } private String getName() { final String operationName = "getName"; try { final String status = (String) mbsc.invoke(objectName, operationName, null, // no parameter null ); return status; } catch (Exception e) { logger.info("Error getting name value from
bean " + e.getMessage()); } return null; } }

This example does not need any Spring classes to access the MBean, even though it is created on the server as a Spring Bean. The test client accesses the MBeanServer via the RMI protocol.

You may notice that in order to make a connection to the MBeanServer, several intermediate objects must be created, such as a JMXServiceURL, a JMXConnector, and a MBeanServerConnection. In the process of creating these objects, checked exceptions must be handled.

This leads me to my final piece of code, which illustrates the same functionality, but is implemented using Spring.

First, here is a client-side Spring configuration file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
 "http://www.springframework.org/dtd/spring-beans.dtd">
 
<beans>
 
<bean id="clientConnector" class=
"org.springframework.jmx.support.MBeanServerConnectionFactoryBean">
  <property name="serviceUrl" value=
"service:jmx:rmi://localhost/jndi/rmi://localhost:1090/myconnector"/>
</bean>
 
<bean id="proxy" class=  
"org.springframework.jmx.access.MBeanProxyFactoryBean">
  <property name="objectName" value="spring:name=jmxBean"/>
  <property name="proxyInterface" value="com.phurnace.JmxBean"/>
  <property name="server" ref="clientConnector"/>
</bean>
 
</beans>
This configuration file configures an MBeanServerConnectionFactoryBean to provide the client with a connection to the server, via the RMI protocol. Then, an MBeanProxyFactoryBean is configured to create a proxy for the MBean registered under the specified ObjectName. Finally, the client connection bean is referenced, to allow remote access. Finally, here is the the Spring client:

package com.phurnace;

import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.
ClassPathXmlApplicationContext; public class TestSpringJmxClient { private static Logger logger = Logger.getLogger
(TestSpringJmxClient.class); private ApplicationContext ctx; private JmxBean jmxBean = null; /** * @param args */ public static void main(String[] args) { org.apache.log4j.BasicConfigurator.configure(); if (args.length == 0) { logger.info("Usage: java com.phurnace.
TestSpringJmxClient "); System.exit(0); } TestSpringJmxClient jmxClient = new TestSpringJmxClient(); jmxClient.init(); jmxClient.accessBean(args[0]); System.exit(0); } public void init() { ctx = new ClassPathXmlApplicationContext
("/com/phurnace/client-jsr160.xml"); if (ctx != null) { logger.info("Successfully loaded
ApplicationContext"); } jmxBean = (JmxBean)ctx.getBean("proxy"); } public void accessBean(String newName) { String name = getName(); if (name == null) { return; } logger.info("Original name is " + name); setName(newName); name = getName(); if (name == null) { return; } logger.info("New name is " + name); logger.info("Rating is " + jmxBean.getRating()); try { jmxBean.setRating(10); } catch (Exception e) { logger.warn("Unable to set rating -
attribute is read-only"); } logger.info("Rating is still " +
jmxBean.getRating()); } private String getName() { return jmxBean.getName(); } private void setName(String name) { jmxBean.setName(name); } }

You might notice that the code is much more concise and clean. Except for the loading of the application context file, and the Bean access, there are no references to Spring code needed.

A try-catch block wraps the call JmxBean.setRating(10), as this method was specifically not exported by the server-side. This essentially makes this property read-only.

Hopefully, this code might encourage you to investigate Spring JMX as a technology worth incorporating in your next application. Providing external access to applications can pay off in valuable, unforseen ways after the it has been deployed.

In Untagged 
Comment (0) Read More...


Posted by: Alexander Bibighaus on

Switching IDE's has always been something I feel is important to keep an open mind about. I learned this early on when I was an emacs fanatic. I started software development in a Unix/C environment where emacs and vi were the two editors of choice (or debate). Despite all of the vi/emacs wars , my experience was that both came in handy, but at different times.

I recently feel this way about Netbeans vs Eclipse in the Java IDE world. Both IDE's contribute different tools to a Java developer that are extremely useful.

Let's take Eclipse for example. I like Eclipse's efficiency. Everything takes less clicks! In addition, the SWT toolkit still feels and performs better than any Java application out there. Netbeans continues to have small quirks about it that cause discomfort for the user because the application does not behave as a normal native application. Something as simple as managing the cursor in the code does not feel natural to me. So, the “Everyday IDE” still goes to Eclipse.

On the flip side, Netbeans has far more integrated tools and wizards than Eclipse. Netbeans has a rich set of wizards and tools for mobility, J2EE, Web development etc. Moreover, the Java Profiler is excellent! The best part about Netbeans is that it is one coherent tool from a single vendor. The “Most Complete IDE” goes to NetBeans.

Netbeans Visual Development tools are the first visual tools for Java I can say I enjoyed. The best part is the ability to integrate manually written code with the visual designer and vice-versa. In addition, the visual designer generates simple code. The generated code is straightforward Java that anyone unfamiliar with the visual tools would understand. The “Most Innovative IDE” goes to NetBeans for finally giving Java a set of useful visual tools.

Eclipse has a one big leg up on Netbeans. Eclipse RCP is a fantastic development framework. It is rich in features and has a unifying effect on product development. Anyone thinking about developing a desktop application should seriously consider Eclipse RCP. The “Best Application Development IDE” goes to Eclipse because you should be developing RCP applications in that case.

In conclusion, just as vi and emacs both brought different ideas as an editor, it is worth the effort to learn both. You will find that rather wasting your time arguing for one or the other, you just have more tools in you tool chest since you tried them both!

In NetbeansIDEEclipse
Comment (0) Read More...


<< Start < Prev 1 2 3 4 Next > End >>