waffel’s Weblog

August 21, 2009

use your own variable in eclipse code templates

Gespeichert unter: java — Thomas Wabner @ 2:08
Tags: , , ,

On my work we develop eclipse plugins and want to add the current bundle id and bundle version to the since field for class comments. There are not much examples around this problem (we have searched google and eclipse help) so let me explain how you can achive this.

For example we want to define follow code template:

/**
 * @author ${user}
 *
 * ${tags}
 * @since ${bundleId} ${bundleVersion}
 */

The bundleId and bundleVersion variable are not provided by the standard code template variables. Now we have to find out how we can achive this problem.

First of all you need to develop your own eclipse plugin which should provide such feature. The new plugin requires follow dependencies:

  • org.eclipse.core.resources;bundle-version=“3.5.0″,
  • org.eclipse.ui;bundle-version=“3.5.0″,
  • org.eclipse.jface.text;bundle-version=“3.5.0″,
  • org.eclipse.jdt.core;bundle-version=“3.5.0″,
  • org.eclipse.jdt.ui;bundle-version=“3.5.0″,
  • org.eclipse.core.runtime;bundle-version=“3.5.0″,
  • org.eclipse.pde.core;bundle-version=“3.5.0″

The PDE dependency is needed to get the current bundle id and the bundle version. If you need other features (for example a maven project version) you have depend on other plugins. But in this example I’ll show you how to add bundle id and bundle version as extra variable for the eclipse code templates.

Next you have to create a extention to register your own variable resolver at startup. The variable resolvers are the heart of the plugin because they providing new variables for the code templates to be used and resolving the content if you use the code template.

plugin.xml:

< ?xml version="1.0" encoding="UTF-8"?>
< ?eclipse version="3.4"?>
<plugin>
   <extension point="org.eclipse.ui.startup">
      <startup class="yourplugin.eclipse.javadoc.internal.RegisterResolvers">
      </startup>
   </extension>
</plugin>

The RegisterResolvers class implements the IStartup interface from eclipse. This class registers the variable resolvers to the code template context. This is required to have the variables available in the code templates from eclipse.

RegisterResolver:

/**
   *
   * {@inheritDoc}
   *
   * @see IStartup#earlyStartup()
   *
   */
  public void earlyStartup() {
    // check if plug-in org.eclipse.jdt.ui is already active
    final Bundle bundle = Platform.getBundle(PLUGIN_ID);
    if (bundle != null && bundle.getState() == Bundle.ACTIVE) {
      // register resolvers
      registerResolvers();
    } else {
      // register listener to get informed, when plug-in becomes active
      final BundleContext bundleContext = Activator.getDefault().getBundle().getBundleContext();
      bundleContext.addBundleListener(new BundleListener() {
        public void bundleChanged(final BundleEvent pEvent) {
          final Bundle bundle2 = pEvent.getBundle();
          if (!bundle2.getSymbolicName().equals(PLUGIN_ID)) {
            return;
          }
          if (bundle2.getState() == Bundle.ACTIVE) {
            registerResolvers();
            bundleContext.removeBundleListener(this);
          }
        }
      });
    }
  }

/**
   *
   * Internal method to register resolvers with all context types.
   *
   */
  private void registerResolvers() {
    final ContextTypeRegistry codeTemplateContextRegistry = JavaPlugin.getDefault().getCodeTemplateContextRegistry();
    final Iterator ctIter = codeTemplateContextRegistry.contextTypes();
    while (ctIter.hasNext()) {
      final TemplateContextType contextType = (TemplateContextType) ctIter.next();
      contextType.addResolver(new BundleIdResolver());
      contextType.addResolver(new BundleVersionResolver());

    }
  }

The bundleIdResolver extends the TemplateVariableResolver and defines (in the default constructor) the variable name which can be used later in the code template, a description and overrides the resolve method.

The resolve method checks if the current project is a plugin project and if so returns the bundle id from the project.

public class BundleIdResolver extends TemplateVariableResolver {
  /**
   *
   * Constructs a new <code>BundleIdResolver</code>.
   *
   */
  public BundleIdResolver() {
    super("bundleId", "id of the bundle containing the current compilation unit");
  }

  /**
   *
   * {@inheritDoc}
   *
   * @see TemplateVariableResolver#resolve(org.eclipse.jface.text.templates.TemplateContext)
   *
   */
  @Override
  protected String resolve(final TemplateContext pContext) {
    final CodeTemplateContext context = (CodeTemplateContext) pContext;
    final IPluginModelBase pluginModelBase = PluginRegistry.findModel(context.getJavaProject().getProject());
    if (pluginModelBase == null) {
      return null;
    }
    return pluginModelBase.getBundleDescription().getSymbolicName();
  }
}

Now you can come up with the question why not you can use the standard eclipse extention point mechanism and create your own context.

Well, we want to extend the java context but the current eclipse implementation doe’s not provide such functionality. For sure if you want to have your own context you can do this with the standard extention point mechanism (as the Ant example). There is a small example about the eclipse editor templates.

Thanks to my colleague Marco Lehmann for the complete solution.

November 28, 2008

how to use EL from java in a JSF 1.2 environment

Gespeichert unter: JSF, java, software — Thomas Wabner @ 9:47
Tags: , , ,

There are not much examples, how to use a ELExpression from your java code. The most examples I found, are focussing on „implement your own ELResolver“. The best documentation comes from SUN in form of tutorials and package/javadoc.

Now I will provide some tips how to deal with EL expressions from java. I have tested and implemented this in a JSF 1.2 web application, where I have access to the FacesContext.

In JSF 1.2 you have access to expression factory:

// get application from faces context
Application app = FacesContext.getInstance().getApplication();
ExpressionFactory exprFactory = app.getExpressionFactory();

Now you can use the expression factory to get a MethodExpression or ValueExpression. In my projects we need very often ValueExpressions.

But first you need also an ELContext. There are many implementations available of such context (for JSP, Faces and so on) and enough documentation how to create your own context.
You can access such context again from the faces context:

// getting the ELContext from faces context
ELContext elContext = FacesContext.getInstance().getELContext();
// creating value expression with the help of the expression factory and the ELContext
ValueExpression valExpr = exprFactory.createValueExpression(elContext, "#{devBean.devMode}", Boolean.class);

In this example I will use the boolean value from a „devBean“ to work later with this value. Of course, you can inject the value expression, required class type and so on.
The last needed thing is to assign the value to a local variable:

Boolean developmentMode = (Boolean) valExpr.getValue(elContext);

Thats it!

September 9, 2008

expanding richfaces tree on datamodel changes

Gespeichert unter: JSF, java — Thomas Wabner @ 2:19
Tags: , , ,

Sometimes you will select a tree node in a richfaces tree, triggered by your datamodel. There are several hints how to do this with a tree state advisor, but I have found another way to do this.

My main problem was, that I do not have a relation between my datamodel and the richfaces UITree components (nodes). This problem was introduced because I use the recursiveTreeAdaptor. I have not found a way to get a TreeRowData object from the UITree for my datamodel object.

I have searched in the richfaces implementation, if there is another way to work with my datamodel which have to expand the tree, if the datamodel is changed.

Lets clearify what I want to do: I have a datamodel with some root nodes and „normal“ nodes in a tree like structure. I have also (in my TreeManager) a parameter which holds a selectedNode. A node can selected from the UI (the user clicks on a tree node and causes a node selection event) or from my datamodel, which calls a method in the TreeManager to select a specific tree node.

The tree manager contains a method to select a specific node like this:

public void select(final Node nextStepNode) {
  this.selectedNode = nextStepNode;

}

To expand the tree to the selected node, I have changed to select method:

public void select(final Node nextStepNode) {
  this.selectedNode = nextStepNode;
  try {
      // walk over the tree which expands the tree and uses a complete tree
      // range
      tree.walk(FacesContext.getCurrentInstance(), expandingDataVisitor, new CompleteTreeRange(), null, null);
    } catch (final IOException e) {
      if (LOG.isErrorEnabled()) {
        LOG.error(String.format("problem %s", e.getMessage()));
      }
    }
}

The tree walk method walks over the tree using my own data visitor and tree range. The tree range implementation tolds the tree to walk also over hidden nodes. You remember? The tree should expand all nodes to the selected node, also if the selected node is hidden.

The tree range implementation looks like:

public class CompleteTreeRange implements TreeRange {

  /**
   * {@inheritDoc}
   */
  @SuppressWarnings("unchecked")
  public boolean processChildren(final TreeRowKey rowKey) {
    return true;
  }

  /**
   * {@inheritDoc}
   */
  @SuppressWarnings("unchecked")
  public boolean processNode(final TreeRowKey rowKey) {
    return true;
  }

Now comes the hard stuff on my solution, the expandingDataVisitor:

public class ExpandingDataVisitor implements DataVisitor {
  public void process(final FacesContext theContext, final Object theRowKey, final Object theArgument)
      throws IOException {
    if (selectedNode.equals(tree.getRowData(theRowKey))) {
      tree.queueNodeExpand((TreeRowKey) tree.getParentRowKey(theRowKey));
    }
}

You can queue node expanding with a tree rowKey to the node, which you want to expand. You don’t need to queue all nodes on the path. The queueNodeExpand method works fine with one rowkey. The row describes itself the complete path to the node. If you use standard jsf ID’s, a possible treeRowKey looks like „jsp123:jsp124:jsp125″ wich is the complete path to your node (row key).

You have to know, that you don’t want expand the selected node (this is in most cases a leafe). You want to expand the tree to the parent of the selected node.

Juni 13, 2008

getting node data from rich tree on user selection

Gespeichert unter: JSF, java, software — Thomas Wabner @ 3:33
Tags: , ,

I have had the problem to get node data from a richfaces tree, if the user selects a node. I have used a recursive tree adapter:

<rich:tree switchType="server"
           stateAdvisor="#{treeStateAdvisor}"
           nodeSelectListener="#{treeMgrt.onSelect}">

   <rich:recursiveTreeNodesAdaptor roots="#{treeMgrt.roots}" var="item" nodes=" {item.nodes}">

     <rich:treeNode>
         <h:outputText value="#{item}"/>
     </rich:treeNode> 

  </rich:recursiveTreeNodesAdaptor>
</rich:tree>

The method in my tree manager onSelect(…) looks like this:

public void onSelect(final NodeSelectedEvent event) {
  final UITree theTree = this.getTree(event);
  if (null == theTree) {
    return;
  }
  final Object rowKey = theTree.getRowKey();
  // this works better
  final Object rowData = theTree.getRowData(rowKey);
  if (rowData instanceof ProductNode) {
    this.selectedNode = (ProductNode) rowData;
  }
}

Normally you can use theTree.getTreeNode(); but with a recursive tree model which method returns alway null. Instead of this I have used the getRowData() method which works for me.
I have filed a bug for richfaces. Hope the problem becomes shortly a solution.

Oktober 9, 2007

Fast stream copy using java.nio channels

Gespeichert unter: java, nio, software — Thomas Wabner @ 11:21
Tags: , , ,

Many times I was asked how to copy fast and simple an input stream to an output stream. I have found a nice solution on koders.com . A programmer named Mr. Hitchens has contributed this code.

Here are my utility method which makes the real fast copy stuff:

public final class ChannelTools {
  public static void fastChannelCopy(final ReadableByteChannel src, final WritableByteChannel dest) throws IOException {
    final ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
    while (src.read(buffer) != -1) {
      // prepare the buffer to be drained
      buffer.flip();
      // write to the channel, may block
      dest.write(buffer);
      // If partial transfer, shift remainder down
      // If buffer is empty, same as doing clear()
      buffer.compact();
    }
    // EOF will leave buffer in fill state
    buffer.flip();
    // make sure the buffer is fully drained.
    while (buffer.hasRemaining()) {
      dest.write(buffer);
    }
  }
}

And how you can use this method to copy an input stream into an output stream? Here comes the answer:


// allocate the stream ... only for example
final InputStream input = new FileInputStream(inputFile);
final OutputStream output = new FileOutputStream(outputFile);
// get an channel from the stream
final ReadableByteChannel inputChannel = Channels.newChannel(input);
final WriteableByteChannel outputChannel = Channels.newChannel(output);
// copy the channels
ChannelTools.fastChannelCopy(inputChannel, outputChannel);
// closing the channels
inputChannel.close();
outputChannel.close()

Bloggen Sie auf WordPress.com.