Who’s On Phirst

Official blog of Phurnace Software.

Archive >> July 2008

Posted by: Shawn Spiars on

The best part about a vacation get-away is the getting away from it all – away from work, away from household chores and getting out of the rat race. The next best thing is coming back home to familiarity – sleeping in your own bed, eating food you recognize, clean restrooms, etc. The “coming back home” experience can be really special when returning from another country where things like food, customs, and various creature comforts are just not the same as in the good old USA. We don’t often appreciate the little things. I think it is healthy to be reminded of what we do have here, by seeing other places.

I recently returned from a week-long trip to Trinidad and Tobago and boy is it nice to be home! Don’t get me wrong – Trinidad is a great place to visit with wonderful people, beautiful tropical forests, and awesome beaches. My visit to Trinidad was not your typical Caribbean island vacation get-away. But, that was by choice. I spent a week in Trinidad with a team of 18 people from my church conducting a Vacation Bible School for children. Before we left the states I was explaining to my 14 year old son how Trinidad is not a third-world country, yet the day we arrived the electricity went out in the town of Gasparillo where we were staying. Consequently, when the electricity went out the household water pump stopped working leaving us with no running water. My son quickly pointed out to me, “Dad, now we are in a third-world country”. Amazing how we all view the world through our own reference point. I must point out, that the locals didn’t freak out a bit.

The driving in Trinidad is either frightening or exhilarating, depending on your point of view. First off, they drive on the left side, or should I say (as an American driver) the “wrong” side of the road. Rarely do they stop at stop signs and when they come to an intersection they all cram their cars in together and aggressively negotiate who goes next by moving their vehicle within inches of each other. Eventually someone gives in, toots their horn and waves the other car in, or yells something like “go on boy”. It just seems to all work. Not really sure how, but it does.

The most beautiful place we visited in Trinidad was Maracas Bay. Even short-term missionaries deserve their day in the sun. We spent a day eating Bake-N-Shark sandwiches, body surfing, and just limin’ on the beach. The waves at Maracas Bay are very powerful and can hurt you if you’re not careful. A teenage girl in our group was pummeled by a large wave and broke her collar bone. As in all new endeavors or experiences -- “be prepared”.

Some of the experiences from my trip that made me really appreciate the things we too often take for granted were the daily cold showers (or no showers), very hot and humid weather (even though Austin does have its share, Trinidad has it beat in that department), no air conditioning, large downpours of rain every day, and tons of mosquitoes. However, none of that dampened our great experience.

In spite of the temporary discomforts in Trinidad, I’ll definitely be going back again. The people were fantastic and we achieved our objectives. Using vacation time to serve others is rewarding and the kindness and friendship returned was well worth the investment.

In Untagged 
Comment (0) Read More...


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.
 

<project name="embedded-ant-example" default="_init">
 
     <target name="sayHello">
 
           <echo>Hello ${to}</echo>
 
     </target>
   </project>
       
     

  • 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 (1) 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...