| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
| <html> |
| <head> |
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> |
| <title>Implementing a New Tag-Based EL Variable Contributor for |
| JSP</title> |
| |
| |
| <meta http-equiv="Content-Style-Type" content="text/css"> |
| <meta http-equiv="Content-Script-Type" content="text/javascript"> |
| <link rel="stylesheet" href="../../book.css" type="text/css"> |
| <link rel="stylesheet" href="default_style.css" type="text/css"> |
| </head> |
| |
| <body> |
| <table summary="" cellpadding="0" cellspacing="0" width="100%"> |
| |
| <tbody><tr valign="bottom"> |
| <td align="left" width="86%"> |
| <h1>Implementing a New Tag-Based EL Variable Contributor for JSP</h1> |
| </td> |
| </tr> |
| </tbody> |
| </table> |
| |
| <hr> |
| <h3>Summary</h3> |
| In this tutorial we will write a plugin that supplies a symbol factory |
| for a fictious JSF tag called "locallyDefinedBean" and see how it works |
| at design time. Our fictious tag adds bean variables to a JSP-JSF |
| page at runtime and we will implemented the logic necessary to simulate |
| this behaviour at design time using the JSF EL framework. Once you |
| finish this tutorial, you should have a basic grasp of what is required |
| to add tooling support for JSF-JSP tags that contribute variables to |
| JSF EL for you own real JSF tag libraries..<br> |
| |
| <h3>Getting Started</h3> |
| |
| To begin, create a blank plugin project by using <span style="font-weight: bold;">File > New > Project</span>... and selecting Plug-in Project. Create the project with all of the defaults:<br> |
| |
| <br> |
| |
| <img alt="plugin project" src="images/new_plugin_project_dialog1.png" style="width: 500px; height: 500px;"><br> |
| <br> |
| |
| Next, open the plug-in dependencies for your project:<br> |
| |
| <br> |
| <img alt="open_manifest_el" src="images/open_manifest_el.png" style="width: 263px; height: 315px;"> |
| <p>Add the plugin dependencies highlighted in yellow below:</p> |
| |
| <img alt="dependency" src="images/add_dependency.png"><br> |
| <p> |
| <span style="font-style: italic;"> |
| </span><span style="font-style: italic;"></span></p> |
| <p>Now we are ready to construct our factory and meta-data extensions. |
| </p> |
| |
| <h3>Constructing the Factory</h3> |
| The symbol factory is delegated the task of constructing your custom |
| design time variables. First, we will create the factory class. |
| <p> |
| Create a new java class in your project by clicking on the src folder and clicking <span style="font-weight: bold;">File > New > Class</span>. |
| Call the class "LocallyDeclaredBeanFactory" and make sure it extends |
| <code>org.eclipse.jst.jsf.context.symbol.source.AbstractContextSymbolFactory</code>. |
| Also be sure enable the check box, <span style="font-weight: bold;">Inherited abstract methods</span>:</p> |
| <br> |
| <img alt="create_factory_class" src="images/create_factory_class.png" style="width: 579px; height: 632px;"><br> |
| <br> |
| Open the new class in the Java editor. You will see two methods |
| automatically generated from the abstract parent class. For the <span style="font-style: italic;">supports</span> method, replace the method with the following:<br> |
| <br> |
| <div class="code"><pre> |
| public boolean supports(IAdaptable context) { |
| return context.getAdapter(IStructuredDocumentContext.class) != null; |
| } |
| </pre> |
| </div> |
| <br> |
| This code tells the framework to only call this factory when the context is adaptable to a structured document context.<br> |
| <br> |
| Next, replace the internalCreate code with the following:<br> |
| <br> |
| <div class="code"> |
| <pre> |
| protected ISymbol internalCreate(String symbolName, int scope, IAdaptable context, List problems) |
| { |
| // get the context |
| final IStructuredDocumentContext sContext = |
| (IStructuredDocumentContext)context.getAdapter(IStructuredDocumentContext.class); |
| |
| // construct a dom resolver for this context |
| final IDOMContextResolver domResolver = |
| |
| IStructuredDocumentContextResolverFactory.INSTANCE.getDOMContextResolver(sContext); |
| |
| // if resolver can be constructed |
| if (domResolver != null) |
| { |
| // get the current node |
| // this is the node marked by our meta-data as contributing an el variable |
| final Node curNode = domResolver.getNode(); |
| |
| // node must be an XML attribute |
| if (curNode instanceof Attr) |
| { |
| final Attr attr = (Attr) curNode; |
| |
| final Node owningElement = attr.getOwnerElement(); |
| |
| |
| //attribute must have a owningElement |
| if (owningElement != null) |
| { |
| |
| IWorkspaceContextResolver workspaceResolver = |
| |
| |
| IStructuredDocumentContextResolverFactory.INSTANCE.getWorkspaceContextResolver(sContext); |
| |
| |
| IProject iProject = workspaceResolver.getProject(); |
| |
| |
| if (iProject != null) |
| { |
| |
| return |
| handleSymbolCreation(symbolName, sContext, attr, owningElement, |
| iProject); |
| } |
| } |
| } |
| } |
| |
| return null; |
| |
| } |
| </pre> |
| </div> |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| <br> |
| |
| |
| |
| |
| |
| |
| |
| |
| You also need to add this private method that does the symbol creation:<br> |
| |
| |
| |
| |
| |
| |
| |
| |
| <br> |
| |
| |
| |
| |
| |
| |
| |
| |
| <div class="code"><pre> |
| private ISymbol handleSymbolCreation(final String symbolName, |
| final IStructuredDocumentContext context, |
| final Attr attr, |
| final Node owningElement, |
| final IProject project) |
| { |
| // create tag lib resolver for this context |
| final ITaglibContextResolver resolver = IStructuredDocumentContextResolverFactory.INSTANCE |
| .getTaglibContextResolver(context); |
| |
| if (resolver == null || !resolver.canResolveContext(context)) { |
| return null; |
| } |
| |
| |
| final String uri = resolver.getTagURIForNodeName(owningElement); |
| IBeanInstanceSymbol beanSymbol = null; |
| |
| // process core taglib |
| if ("http://oracle.com/tutorial/fake/taglib".equals(uri)) { |
| final String elementName = owningElement.getLocalName(); |
| final String attrName = attr.getName(); |
| |
| // protect ourselves by ensuring we are in the var attribute of |
| // a locallyDeclaredBean |
| if ("locallyDeclaredBean".equals(elementName)) { |
| if ("var".equals(attrName)) { |
| |
| final NamedNodeMap attrMap = |
| owningElement.getAttributes(); |
| |
| final Node baseNameNode = |
| attrMap.getNamedItem("classname"); |
| |
| |
| if (baseNameNode instanceof Attr) |
| { |
| |
| // get the name of the bean's class |
| |
| final String |
| className = ((Attr)baseNameNode).getValue(); |
| |
| // create a new empty bean instance symbol |
| // this will encapsulate all of the design time information |
| // about our new variable |
| beanSymbol = |
| SymbolFactory.eINSTANCE.createIBeanInstanceSymbol(); |
| |
| |
| // name the new variable after the value of the var attribute |
| // in the tag |
| |
| beanSymbol.setName(attr.getValue()); |
| |
| // next, we will ask JDT to resolve the class name to a type |
| try |
| { |
| |
| IJavaProject javaProject = JavaCore.create(project); |
| IType type = javaProject.findType(className); |
| |
| // don't bother setting a type descriptor if we |
| // can't find a type |
| if (type != null) |
| { |
| // now we must create a type descriptor that encapsulates |
| // the specific type information about our bean |
| IJavaTypeDescriptor2 javaTypeDescriptor = |
| SymbolFactory.eINSTANCE.createIJavaTypeDescriptor2(); |
| javaTypeDescriptor.setType(type); |
| beanSymbol.setJavaTypeDescriptor(javaTypeDescriptor); |
| } |
| } |
| catch (JavaModelException jme) |
| { |
| // could not construct |
| // fall-through |
| } |
| // finally, add a description that will appear in the content assis |
| // drop-down, to prove that it really worked |
| beanSymbol.setDetailedDescription("Hello world, this is my first tag variable factory"); |
| } |
| } |
| } |
| } |
| |
| return beanSymbol; |
| } |
| </pre></div> |
| <br> |
| <br> |
| <p>You may need to hit Ctrl-O to organize your imports.</p> |
| |
| Save the class and check that it compiles.<br> |
| <br> |
| |
| <h3>Adding the Meta-data</h3> |
| Our ultimate goal is to make a tag like this:<br> |
| <div class="code"><pre><t:locallyDeclaredBean var="x" classname="beans.MyBean"/><br></pre></div> |
| |
| <p>declare a variable called "x" to the tooling which corresponds to a bean |
| of type "beans.MyBean". In order to tell the framework this, we |
| must use meta-data to annotate the t:locallyDeclaredBean. <br> |
| </p> |
| <p>First we create a new folder in our project called metadata:<br> |
| </p> |
| |
| <p><img alt="add_meta_data_folder" src="images/add_meta_data_folder.png" style="width: 438px; height: 578px;"><br> |
| </p> |
| |
| |
| |
| |
| |
| <p>Next use right-click on the project click <span style="font-weight: bold;">File > New > File</span> to create a new meta-data xml file:<br> |
| </p> |
| |
| |
| |
| |
| |
| <p><img alt="add_metadata_file" src="images/add_metadata_file.png" style="width: 438px; height: 578px;"><br> |
| </p> |
| |
| |
| |
| |
| |
| <p>Open the file as source and copy the following markup into the editor:<br> |
| </p> |
| |
| |
| |
| |
| <div class="code"> |
| <pre> |
| <?xml version="1.0" encoding="UTF-8"?> |
| <md:metadatamodel |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" |
| xmlns:md="http://org.eclipse.jst.jsf.common.metadata/metadata.ecore" |
| xmlns:mdt="http://org.eclipse.jst.jsf.common.metadata/metadataTraitTypes.ecore" |
| id="http://oracle.com/tutorial/fake/taglib"> |
| |
| <entity id="locallyDeclaredBean"> |
| <entity id="var"> |
| <trait id="contributes-value-binding"> |
| <value>true</value> |
| </trait> |
| <trait id="value-binding-scope"> |
| <value>request</value> |
| </trait> |
| <trait id="value-binding-symbol-factory"> |
| <value>tutorial.locallyDeclaredBean</value> |
| </trait> |
| </entity> |
| </entity> |
| |
| </md:metadatamodel> |
| </pre> |
| </div> |
| |
| |
| |
| |
| <p>Notice the entities and traits. The "var" attribute <code>entity</code> is a child of the "locallyDeclaredBean" <code>entity</code>. |
| The property |
| "value-binding-symbol-factory" is what points the framework to our |
| factory. However the value here is not the factory itself, but an |
| id for its extension, which we'll define in the next section.</p> |
| |
| |
| |
| |
| |
| <br> |
| |
| |
| |
| |
| |
| <h3>Implementing the extensions</h3> |
| |
| |
| |
| |
| |
| Two extension points work together to declare our symbol factory. |
| First we will extend an extension point to declare |
| the meta-data that we just defined to the framework. Second, we will |
| register the factory id.<br> |
| |
| |
| |
| |
| |
| <br> |
| |
| |
| |
| |
| |
| Open the plugin.xml editor for the project and select the <span style="font-weight: bold;">Extensions </span>tab, click <span style="font-weight: bold;">Add...</span> and select <span style="font-weight: bold;">org.eclipse.jst.jsf.common.standardMetaDataFiles</span>. Right click on the new extension element in the tree on the left and add a new <span style="font-weight: bold;">standardMetaDataFile</span> entry. Enter the uri and location information as shown.<br> |
| |
| |
| |
| |
| |
| <br> |
| |
| |
| |
| |
| |
| <img alt="annotation ext point" src="images/add_annotation.png" ><br> |
| |
| |
| |
| |
| |
| <br> |
| |
| |
| |
| |
| |
| Adding this extension point tells the framework to look in our |
| tutorial-metadata.xml file when queried for metadata about a tag |
| library with the identifying uri |
| http://oracle.com/tutorial/fake/taglib. Note the strange name of |
| the uri in this case. That is to emphasize that they tag library |
| we are creating a tag variable for doesn't really exist -- it's just |
| for this tutorial.<br> |
| |
| |
| |
| |
| |
| <br> |
| |
| |
| |
| |
| |
| Next, we need to declare an extension to <span style="font-weight: bold;"><a href="../extpts_reference/jsf/org_eclipse_jst_jsf_common_contextSymbolFactory.html">org.eclipse.jst.jsf.common.contextSymbolFactory</a></span> that declares our factory and gives it a unique id:<br> |
| |
| |
| |
| |
| |
| <br> |
| |
| |
| |
| |
| |
| <img alt="add symbol factory" src="images/add_symbol_factory.png"><br> |
| <p> |
| Notice that the value we put in the <span style="font-weight: bold;">factory</span> |
| property matches what is in the "value-binding-symbol-factory" metadata |
| property. These values must match so that the framework can find |
| our factory.</p> |
| <p>We are now finished with defining our tag contributor (easy |
| huh?). But we're not quite finished. We need to construct a |
| dynamic web project complete with our fake tag library to test out what |
| we've done.</p> |
| |
| <h3>Setting Up the Dynamic Web Project</h3> |
| First we need to launch a new runtime workbench with our plugin installed. To do this, execute <span style="font-weight: bold;">Run > Run...</span> to create a new launch profile. Create a new Eclipse Application and launch it with the defaults:<br> |
| <p> |
| <img alt="run workbench" src="images/run_workbench.png" style="width: 800px; height: 640px;"> <br> |
| |
| |
| |
| |
| |
| <br> |
| |
| |
| |
| |
| |
| Once the workbench has loaded, go to <span style="font-weight: bold;">New > Project > Other</span> and select <span style="font-weight: bold;">Web > Dynamic Web Project</span> and hit <span style="font-weight: bold;">Next</span>.<br> |
| |
| |
| |
| |
| |
| <br> |
| |
| |
| |
| |
| |
| Name the project and hit next. From the <span style="font-weight: bold;">Project Facets</span> wizard page, enable the <span style="font-weight: bold;">JavaServer Faces </span>facet and click <span style="font-weight: bold;">Next</span>. Click <span style="font-weight: bold;">Next</span> at the <span style="font-weight: bold;">Web Modules </span> page leaving the defaults unchanged. Last you will come to the <span style="font-weight: bold;">JSF Capabilities</span> |
| page. Here you need to set up your JSF Libraries (see user's |
| guide for more details on JSF Libraries). When you are done, |
| click <span style="font-weight: bold;">Finish</span>. This should create a skeletal JSF project. Next we will add the "fake" tag library.<br> |
| |
| |
| |
| |
| <br> |
| |
| |
| |
| |
| <h3>Adding the demonstration tag library</h3> |
| |
| |
| |
| |
| Right-click on the META-INF folder under the WebContent folder in your new Dynamic Web Project and select <span style="font-weight: bold;">New > File</span> and name the file tutorial.tld and save the following into it:<br> |
| |
| |
| |
| |
| <br> |
| |
| |
| |
| <div class="code"> |
| <pre><?xml version="1.0" encoding="ISO-8859-1" ?><br><br><!DOCTYPE taglib<br> PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"<br> "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd"><br><br><br><taglib><br><br><br> <!-- ========== Tag Library Description Elements ========================= --><br><br><br> <tlib-version>1.0</tlib-version><br> <jsp-version>1.2</jsp-version><br> <short-name>tutorial</short-name><br> <uri>http://oracle.com/tutorial/fake/taglib</uri><br> <description><br> An tld to help demonstrate how to implemented tag contributed EL variables.<br> NOTE: this is a taglib for demonstration purposes: it is not fully or correctly<br> implemented and it is not intended to be run in real JSP applications<br> </description><br> <tag><br><br> <name>locallyDeclaredBean</name><br> <tag-class>foo</tag-class><br> <tei-class>foo</tei-class><br> <body-content>empty</body-content><br> <description><br> Tag declares a new bean variable at request scope based on the name <br> and classname provided.<br> </description><br><br> <attribute><br> <name>var</name><br> <required>true</required><br> <rtexprvalue>false</rtexprvalue><br> <description><br> The name of the locally declared variable. This name will be added<br> to the EL variable namespace for the JSP in which it is used at request scope<br> </description><br> </attribute><br><br> <attribute><br> <name>classname</name><br> <required>true</required><br> <rtexprvalue>false</rtexprvalue><br> <description><br> The fully qualified name of the Java class that will be instantiated as<br> the backing bean for the locally declared bean.<br> </description><br> </attribute><br> </tag><br> <br></taglib><br><br></pre> |
| </div> |
| |
| |
| and save and close the file.<br> |
| |
| |
| <br> |
| |
| |
| Create a simple bean called <span style="font-weight: bold;">beans.MyBean</span> in the src folder and paste in the following code:<br> |
| |
| |
| |
| <div class="code"><pre>package beans;<br><br>public class MyBean <br>{<br> public String getFooProperty()<br> {<br> return "foo!";<br> }<br>}<br></pre></div> |
| |
| |
| <br> |
| |
| |
| <h3>Create the Test JSP<br> |
| </h3> |
| |
| |
| |
| Now we will create a test JSP file by right-clicking on the <span style="font-weight: bold;">WebContent</span> folder and clicking <span style="font-weight: bold;">New > Other</span> and in the tree selecting <span style="font-weight: bold;">Web > JSP</span>. Select the defaults and click finish. Then, open the file and replace the contents with the following:<br> |
| |
| |
| |
| <br> |
| |
| |
| <div class="code"> |
| <pre><%@page contentType="text/html"%> |
| <%@page pageEncoding="UTF-8"%> |
| <%-- |
| >The taglib directive below imports the JSTL library. If you uncomment it,<br/>you must also add the JSTL library to the project. The Add Library... action on Libraries node in Projects view can be used to add the JSTL 1.1 library. |
| --%> |
| |
| <%@taglib uri="http://java.sun.com/jsf/core" prefix="f"%> |
| <%@taglib uri="http://java.sun.com/jsf/html" prefix="h"%> |
| <%@taglib uri="http://oracle.com/tutorial/fake/taglib" prefix="t" %> |
| |
| |
| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
| "http://www.w3.org/TR/html4/loose.dtd"> |
| |
| <html> |
| <head> |
| <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> |
| <title>JSP Page</title> |
| </head> |
| <body> |
| <f:view> |
| <h1>JSP Page</h1> |
| <!-- no errors --> |
| <t:locallyDeclaredBean var="x" classname="beans.MyBean"/> |
| <h:outputText value="#{}"/> |
| </f:view> |
| </body> |
| </html></pre> |
| </div> |
| <p> |
| Note a few things. First, we have a taglib declared for our "fake" |
| tag library with prefix "t". Second, we have declared a bean |
| using the locallyDeclaredBean tag to declare a variable "x" of the type "beans.MyBean" that we created above.</p> |
| <p>So now let's test it. Position your cursor inside the empty "{}" |
| braces in the value attribute of the outputText tag. Type |
| Ctrl-Space to request content assist. You should see your bean |
| "x" in the list:<br> |
| |
| <br> |
| |
| <img alt="content assist" src="images/content_assist_1.png" style="width: 938px; height: 277px;"> |
| |
| <p>You can try requesting content assist for the property we added in the bean by typing a period after the "x":</p> |
| |
| <p> |
| <img alt="content assist 2" src="images/content_assist_2.png" style="width: 623px; height: 194px;"><br> |
| |
| </p> |
| <p> |
| Select the property so that the EL text reads "x.fooProperty". Finally, right-click on the JSP file in the <span style="font-weight: bold;">File Explorer</span> and select <span style="font-weight: bold;">Validate</span> to prove that your variable and property are recognized correctly by the validation framework.<br> |
| </p> |
| <h3>Conclusion</h3> |
| <p>We hope this tutorial has helped you understand how to use the JSF |
| tooling to add design time support for your JSF component tag libraries |
| that contribute EL variables. If you need further help or have |
| trouble with this tutorial please post to our web forum on |
| eclipse.org. Putting "EL Variable Contributor" in the subject |
| will ensure speedier response from knowledgeable parties.</p> |
| </body></html> |