Wednesday December 06, 2006
I'll get him back someday somehow.
|
|
Sunday October 15, 2006 



public void init() {
...
// Perform application initialization that must complete
// *after* managed components are initialized
// TODO - add your own initialization code here
/**
* We need to build an Array from the subparts of the car to use in the dataprovider
*/
ArrayList engines = new ArrayList();
try {
boolean moreRows = myWebServiceGetCars1.cursorFirst();
RowKey currentRowKey = null;
FieldKey engineKey = myWebServiceGetCars1.getFieldKey("engine");
while(moreRows) {
currentRowKey = myWebServiceGetCars1.getCursorRow();
Engine currentEngine = (Engine)myWebServiceGetCars1.getValue(engineKey, currentRowKey);
engines.add(currentEngine);
moreRows = myWebServiceGetCars1.cursorNext();
}
} catch (DataProviderException dpe) {
error("DataProviderException=" + dpe);
}
this.objectArrayDataProvider1.setArray((Engine [])engines.toArray(new Engine [0]));
}



|
|
Tuesday October 03, 2006 



public void prerender() {
/**
* Some logic to check for read only. For now, set to true.
*/
boolean readOnly = true;
if(readOnly) {
this.getSessionBean1().setTextFieldDisabled(true);
}
}

|
|
Friday August 25, 2006
|
|
Wednesday August 23, 2006 



In order to refresh
the web service in the IDE scope, if you want to use the same name, you
need to delete the web service and re-add it. If you are OK with
keeping multiple versions of the web service around, you don't have to
delete the old one. Simply add the new one. The new name
will have a number postfixed that will be incremented each time you add
the same named web service.

|
|
Wednesday August 16, 2006 

| Scenario 1 - One user changes a
component on the JSP page Description: User1 has Page1 open that shows a static text field saying "Hello World". User2 opens Page1 of the same project, changes "Hello World" to "I like Ice Cream". User2 then "commits" the change through CVS in Creator. Result: If User1 does a CVS "update", when they do any action in the visual designer that requires a refresh, they will see the static text saying "I like Ice Cream". User1 can also refresh the page to see the changes. Tips: User2 must "Save" his changes before committing. The CVS commit action will not automatically save everything changed. |
| Scenario
2 - Two users change the
same component on the JSP page Description: User1 has Page1 open that shows a static text field saying "Hello World". User2 opens Page1 of the same project, changes "Hello World" to "I like Ice Cream". User2 then "commits" the change through CVS in Creator. User1 changes the Page1 static text field to say "I hate Ice Cream". User1 then "commits" the change through CVS in Creator. Result: User1 will see the following log. cvs commit: Examining sharedapplication1The key is "Up-to-date check failed for `sharedapplication1/web/Page1.jsp". User1 needs to do a CVS "update" to get past this problem. When User1 does an update, they'll see output similar to this. ![]() There will be a conflict "C" between the changes. To resolve the conflict, on the "Versioning" window, select the file in question, right-click and choose "Resolve Conflicts". You'll be presented with a window like the following.
User1 needs to choose which change they want from the right or left window and select "Accept" in that window. Tips:
|
| Scenario 3 - One user changes
Page1.java Description: User1 has Page1.java open. User2 opens Page1.java and adds a method "getIceCream()". User2 commits the changes. Result: If User1 does a CVS "update", they will see the method "getIceCream()" in Page1.java. Tips:
|
| Scenario 4 - Two users changes
Page1.java Description: User1 has Page1.jsp open in the visual designer. User2 opens Page1.java and adds a method "getIceCream()". User2 commits the changes. User1 double-clicks a button and is looking at the action method for the button in Page1.java. User1 adds code to the action method and commits the change. Result: If User1 does a CVS "commit", they will see the following in the output window. cvs commit: Up-to-date check failed for `Page1.java' cvs [commit aborted]: correct above errors first!If User1 does a CVS "update", they'll see something like the following. ![]() You'll notice the changes were "Merged" in Page1.java. |
| Scenario 5 - One user changes page navigation Description: User1 has the navigation editor open. User2 adds "Page2" and adds a navigation rule from the button on "Page1" to "Page2". User2 then does a CVS "add" for Page2.jsp and Page2.java. User2 then does a CVS "commit". Result: Three files will be modified;
If User1 does a CVS "update", the will see the new page in the navigation rule in the navigation editor. Tips:
|
| Scenario 5 - Two users changes page navigation Description: User1 has the navigation editor open and adds "Page3". User1 then adds a button to "Page2" and draws a navigation from "Page2" button to "Page3". User2 has the navigation editor open and adds "Page4". User2 adds a navigation rule from the "Page2" button to "Page4". User2 then does a CVS "add" for Page4.jsp and Page4.java. User2 then does a CVS "commit". Result: Three files will be modified;
If User1 does a CVS "commit", the will see an up-to-date error. User1 will then have to do a CVS "update". After doing the CVS "update", User1 will see the following in the VCS output window. ![]() As you can see, there will be conflicts in the managed-beans.xml as well as the navigation.xml. Also, the merge last the navigation User2 put in going from "Page2" to "Page4". If you "Resolve Conflicts" on the managed-beans.xml, you'll see the this dialog. ![]() Resolving the managed-beans.xml Conflicts You can see that the merge couldn't distinguish that both User1 and User2 added a page. To get out of this situation, User1 will need to "Accept" the "Working File", the one on the left, then re-add the managed-bean entry for Page4. Before User1 accepts, User1 must copy the "Revision x.x" pink highlighted text by highlighting the text and hitting "CTL-C". User1 must then open the "managed-beans.xml" file from the "Files" window under "web->WEB-INF" and near the end of the right before the </faces-config> tag and do a paste "CTL-V". Resolving the navigation.xml Conflicts The merge also leaves the navigation.xml file broken. To fix this, User1 will need to accept the "working file" changes then re-add the navigation link from a new button on "Page2" to "Page4". Tips:
This technique involves having multiple navigation files. The problem with this solution is that Java Studio Creator will only recognize the "navigation.xml" file when the visual navigation editor is opened. This means only one developer will be able to visually edit the navigation file. Steps to create multiple navigation files.
![]() |
|
|
Wednesday August 09, 2006 
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/CorporateTravelCenter" docBase="CorporateTravelCenter"
debug="5" reloadable="true" crossContext="true">
<Resource name="jdbc/Travel" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="travel" password="travel" driverClassName="org.apache.derby.jdbc.ClientDriver"
url="jdbc:derby://localhost:21527/sample"/>
</Context>
|
|
Saturday August 05, 2006 <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<web-app version="2.4">
org.dom4j.DocumentException: Error on line 3 of document : Document is invalid: no grammar found. Nested exception: Document is invalid: no grammar found.
at org.dom4j.io.SAXReader.read(SAXReader.java:482)
at org.dom4j.io.SAXReader.read(SAXReader.java:365)
at com.liferay.portal.service.impl.PortletLocalServiceImpl._readWebXML(PortletLocalServiceImpl.java:983)
at com.liferay.portal.service.impl.PortletLocalServiceImpl.initWAR(PortletLocalServiceImpl.java:259)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
private List _readWebXML(String xml) throws DocumentException, IOException {
List servletURLPatterns = new ArrayList();
if (xml == null) {
return servletURLPatterns;
}
SAXReader reader = new SAXReader(true);
reader.setEntityResolver(new EntityResolver());
=====> Document doc = reader.read(new StringReader(xml));
Element root = doc.getRootElement();
Iterator itr = root.elements("servlet-mapping").iterator();

|
|
Friday August 04, 2006 Sun Java Studio Creator 2 takes advantage of the NetBeans Platform Version Control System (VCS). Specifically, Creator supports CVS and Visual Source Safe(VSS). I'll be focusing some blog entries on doing version control using Creator and CVS.
Creator web applications consist of files organized at the project level. The project file structure can be seen in the "Files" window next to the "Projects" window.
Before adding a project to CVS, you must make sure all the necessary files are part of the project. You don't want logical references outside the project structure. The NetBeans project structure supports a logical library reference. A library reference is a collection of Jar files. Creator ships with some standard library references that are part of each developers environment. To make a project “portable” you must be careful defining library references. Library references are typically defined either at the user level or at the System level. This means if you define a library reference, that library reference definition will be in your user directory and not in the project file structure. If you need to add Jar files to your project, avoid using libraries references. Instead, you need to add the Jar file to a directory within the project structure. For example, if you are using the Hibernate framework and want to add “hibernate3.jar” to your project, you would do the following.
AJAX Components
When you drop an AJAX component on a web page in Creator, Jar files are added to the project directory “lib/complibs”. Also, a library reference is created to reference this set of Jar files. The library reference is created in your user directory. If you open your library references and select the AJAX Blueprint that was created, you'll see something similar to the following.

When the first AJAX component is dropped on the designer, a library reference is created in your user directory. The file where the library reference is created is "build.properties". Since the user directory can't be included with the project, you'll need to take steps to add the Jar references that were added to the project "lib/complibs" to the project libraries. To do this, right-click on the "Libraries" node under the "Project" window and select "Add JAR/Folder..." like this.




At this point, your project should be ready to add to CVS. Please check out the article, "Source Code Control in the Sun Java Studio Creator 2 IDE" for details on setting up CVS and adding your project.
IMPORTANT - The only tip I would add to this is about ignoring certain files. For sure you want to ignore the "nbproject\genfiles.properties" from CVS since it represents IDE session specific information. To do this, go to the "Versioning" window next to the "Palette" window. Select the "genfiles.properties" file under the "nbproject" directory. Right-click on the file and select "CVS->ignore". This will create a ".cvsignore" file in the "nbproject" directory for that file.
|
|
Sunday July 23, 2006 public void prerender() {
if(mySpecialCondition) {
setFields(this.getPage1());
}
}
private void setFields(UIComponent inComponent) {
/**
* If this component has children, set the properties then recurse through each child
* to see if they have children to be set.
*/
List allComponents = inComponent.getChildren();
if(null == allComponents) return;
Iterator listIterator = allComponents.iterator();
UIComponent currentComponent = null;
while(listIterator.hasNext()) {
currentComponent = (UIComponent)listIterator.next();
if(null != currentComponent) {
if(currentComponent instanceof TextField) {
((TextField)currentComponent).setReadOnly(true);
} else if(currentComponent instanceof TextArea) {
((TextArea)currentComponent).setReadOnly(true);
} else if(currentComponent instanceof Button) {
((Button)currentComponent).setVisible(false);
}
/**
* Recurse through all the components
*/
this.setFields(currentComponent);
}
}
}
Of course you would need to change the set of components and properties
to fit your needs. Also the scope of the components to be changed
could be controlled by using a container (Layout) such as a group panel.
|
|
Thursday July 20, 2006 /*The template for this page looks like this at the top.
* Page1.java
*
* Created on June 20, 2006, 9:36 AM
* Copyright david
*/
/*So where do you change the "_USER_" tag. Basically this is defined in the "tools->options(advanced)". The node is "Editing->Java Sources". The dialog looks like this.
* __NAME__.java
*
* Created on __DATE__, __TIME__
* Copyright __USER__
*/

/*So changing the "_USER_" macro in this case would change the "@author" tag value.
* NewClass.java
*
* Created on July 20, 2006, 2:23 PM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package com.sun;
/**
*
* @author david
*/
public class NewClass {
/** Creates a new instance of NewClass */
public NewClass() {
}
}
|
|
Friday June 23, 2006 | Attempting to add portlet.tld
to war... Adding portlet.tld to war... ERROR: java.util.zip.ZipException: duplicate entry: WEB-INF/tld/portlet.tld org.apache.jetspeed.deployment.DeploymentException: java.util.zip.ZipException: duplicate entry: WEB-INF/tld/portlet.tld at org.apache.jetspeed.deployment.impl.DeployPortletAppEventListener.deployPortletApplication(DeployPortletAppEventListener.java:173) at org.apache.jetspeed.deployment.impl.DeployPortletAppEventListener.invokeDeploy(DeployPortletAppEventListener.java:158) at org.apache.jetspeed.deployment.impl.StandardDeploymentManager.dispatch(StandardDeploymentManager.java:257) at org.apache.jetspeed.deployment.impl.StandardDeploymentManager.deploy(StandardDeploymentManager.java:168) at org.apache.jetspeed.deployment.impl.StandardDeploymentManager.fireDeploymentEvent(StandardDeploymentManager.java:202) at org.apache.jetspeed.deployment.impl.StandardDeploymentManager$FileSystemScanner.run(StandardDeploymentManager.java:342) Caused by: java.util.zip.ZipException: duplicate entry: WEB-INF/tld/portlet.tld at java.util.zip.ZipOutputStream.putNextEntry(ZipOutputStream.java:163) at java.util.jar.JarOutputStream.putNextEntry(JarOutputStream.java:90) at org.apache.jetspeed.tools.deploy.JetspeedDeploy.addFile(JetspeedDeploy.java:277) at org.apache.jetspeed.tools.deploy.JetspeedDeploy.<init>(JetspeedDeploy.java:170) at org.apache.jetspeed.deployment.impl.DeployPortletAppEventListener.deployPortletApplication(DeployPortletAppEventListener.java:168) ... 5 more ERROR: Failure deploying C:\Apache Jetspeed 2.0\webapps\jetspeed\WEB-INF\deploy\ Portlet3.war |



|
|
Friday June 16, 2006
|
|
Friday May 12, 2006
|
|
Thursday May 11, 2006 


Feature
|
Description
|
|---|---|
datahandleronly
|
always map attachments to the
DataHandler type
|
donotoverride
|
do not regenerate classes
that already exist in the classpath
|
donotunwrap
|
disable unwrapping of
document/literal wrapper elements in WSI mode (default)
|
explicitcontext
|
turn on explicit service
context mapping ( generates SOAP headers)
|
jaxbenumtype
|
Map anonymous enumeration to
its base type
|
nodatabinding
|
turn off data binding for
literal encoding
|
norpcstructures
|
do not generate RPC
structures (
-import only)
|
novalidation
|
turn off full validation of
imported WSDL documents
|
resolveidref
|
resolve
xsd:IDREF
|
searchschema
|
search schema aggressively
for types
|
strict
|
generate code strictly
compliant with JAXRPC spec
|
unwrap
|
enable unwrapping of
document/literal wrapper elements in WSI mode
|
wsi
|
enable WSI-Basic Profile
features, to be used for document/literal and rpc/literal
|


|
|
|
|
Monday May 08, 2006 





|
|
Thursday May 04, 2006
The demo gods where not
with me. I did a demo that I've literally done at least 50
times. Can you believe the demo crashed! Ugh!
I tried to pull a Tor
Norbye demo save but failed so I couldn't do the Tor-Nixon
victory salute. As I sat watching the next presentation my
blunder came to mind. I really wanted to run on stage, push
the presenter out of the way and show the crowd how the demo worked.
In the end the demo went well as I was able to show all the
features I intended. For those of you reading this that wonder what I
did wrong, I didn't include the "Travel:prerender" codeclip which
affected the CachedRowset parameter the FIRST time the page is
show. I even got to throw out some shirts and squishy Dukes.
I always wanted to do that!
Despite some difficulty
understanding them, they are truly wonderful!
|
|

|
|
Java Studio Creator 2 Update 1 is out!
This version can run side by side with Java Studio Creator 2.
This version includes:
Check it out at the Creator downloads page.
Posted by David Botterill ( May 04 2006, 06:40:11 PM MDT ) Permalink Comments [5]
|
|
Wednesday April 19, 2006 Yes I'm still alive. I've been very busy traveling and preparing to travel.
I wanted to make sure the news got out about the new Java Studio Creator 2 AJAX components. You can read all about them here.
Basically the new components are:
You can get them quickly by simply going to the update center as described on the link above.
Posted by David Botterill
( Apr 19 2006, 04:04:03 PM MDT )
Permalink
|
|
Tuesday March 14, 2006 The Creator content team has done a great job with the Creator web site (http://developer.sun.com/jscreator). They've been struggling with the daunting task of trying to guess how people think and how they approach the web site to look for information.
Recently a "Search Java Studio Creator" search capability has been added to the Overview tab of the Creator web site to help developers find information. As with many site searches you can get too much information that in the end makes finding what you want more difficult. Hopefully this blog will help.
Does Google Do a Better Job?
I did some testing searching for the term "data provider". Here's the Google advanced search criteria I used. You can see that I specified "developer.sun.com" as the Domain.

The results where 26 hits. Only one of the hits was actually on the Creator part of "developer.sun.com". So the Google search really doesn't do what I want. I really just want to search the Creator part of the "http://developer.sun.com" web site which is really "http://developer.sun.com/jscreator".
Using the Search at "http://developer.sun.com/jscreator"
The search on the Creator site is show below.


112 Results found for "data provider, +url:http://developers.sun.com/prodtech/javatools/jscreator/" in the "Developer - Reference" tab
I think this
must be a
defect in the results display. The actual result number is 110.
http://onesearch.sun.com/search/onesearch/index.jsp?charset=UTF-8
&qt=data+provider%2C%2Burl%3Ahttp%3A%2F%2Fdevelopers.sun.com%2Fprodtech%2Fjavatools%2Fjscreator%2F%2C+-url%3Ahttp%3A%2F%2Fdevelopers.sun.com%2Fprodtech%2Fjavatools%2Fjscreator%2Freference%2Fdocs%2Fhelp
&qp=language%3Aen%2C+%7C%7C+doctype%3Apdf%2Cdoctype%3Ahtml%2Cdoctype%3Axml%2Cdoctype%3Aplain
&rt=1
&cs=0
&nh=100
&rf=0
&col=developer-reference
I've
done the
line breaks to show the different "GET" parameters. You'll
recognize the "&nh=100" is the number of results per page.
The "&qt" is the query text. So conceivably
you could
bookmark this URL and simply change the "data+provider" to the phrase
you want to find. Again remember that the URL semantics could
change and this bookmark could break.
|
|
Thursday February 02, 2006 Problem
Here's a typical scenario. You have a drop down list and one or more static text fields. You also have a text field and a button. You want the value of the static text field to changed based on the value selected on the drop down list. You also want the text field to be required when the user presses the button. So you select the drop down list “Auto-submit On Change” and the text field to required. The Creator 2 designer would look something like this.
The effect of this situation causes the text field validation to trigger the “required” when you select a new value for the drop down list. The figure below shows a snapshot of the results of selecting a value from the drop down list.
Solution
There are a couple of ways to address this problem. The overall term for what is being done is called “Conditional Validation”. Conditional Validation should be used when you need to do validation based on logic that goes beyond defining a validator for a field.
First, I need to give the credit for the following solutions to Jayashri Visvanathan and Matt Bohm. Jayashri is an engineer on the Creator 2 team. She has in-depth knowledge of JavaServer Faces since she worked on the JavaServer Faces team with Craig McClanahan. Matt is also a Creator engineer who was in on the ground work of the data providers and the inventor of the virtual forms. He also has in-depth knowledge of the JavaServer Faces life cycle.
Option 1 – Logic in the Action Method
”In your JSF application built using Creator, you might run into a scenario where you want to execute validators only upon button click and not when form submission happens via JavaScript (for example when turn on autosubmit on change on a drop down list). In this case you won't be able to attach any validators on your input components because once you attach them, they will always get executed during “ProcessValidations” phase irrespective of whether the postback happened via button click or form submission. So the work around is to do conditional validation upon button click. So in your button's action handler, you validate your input field and if it failed, return "null" as outcome from your action handler to tell the JSF framework to redisplay the same page instead of processing the navigation rules for the current view. Here is the sample code you can add to your action handler to ensure that textfield is not null when the page is submitted via button click.” - Jayashri
if (textField1.getValue() == null || textField1.getValue().equals("")) {
FacesMessage message = new FacesMessage("Textfield1 is required. Enter a value");
message.setSeverity(FacesMessage.SEVERITY_ERROR);
getFacesContext().addMessage(textField1.getClientId(getFacesContext()), message);
return null;
}
return "success";
With Jayashri's solution, you need to make sure “required” is not selected for the component you are validating.
Option 2 – Logic in The Preprocess Method Before “ProcessValidations”
Matt's solution is implemented differently. Matt's solution will change the required attribute of a component in the “preprocess()” method of the page which happens before the JSF “ProcessValidations”. Here's the designer shot of Matt's layout.
In Matt's example, you don't want to validate the drop down list unless the user presses the “Next Page-->” button. If the user presses the “<--Previous Page” button, you don't want to validate the drop down list but rather allow the user to navigate back. Here's the code that will accomplish this.
public void preprocess() {
FacesContext context = FacesContext.getCurrentInstance();
Map map = context.getExternalContext().getRequestParameterMap();
if (map.containsKey(nextButton.getClientId(context))) {
shippingMethodDropDown.setRequired(true);
} else {
shippingMethodDropDown.setRequired(false);
}
}
The request parameter map is obtained and checked to see if it contains the “nextButton”. If it does, this means the button was pressed and the drop down list is set to “required”. Otherwise, the drop down list is set to NOT “required”.
Again, thanks go to Jayashri and Matt!
Cheers!
-David
Posted by David Botterill
( Feb 02 2006, 09:19:23 PM MST )
Permalink
|
|
Wednesday February 01, 2006 java.sql.SQLException: [sunm][SQLServer JDBC Driver]This driver is locked for use with embedded applications
This exception is thrown from the “smsqlserver.jar” SQLServer JDBC driver. This driver is meant to be used within the SJSAS PE bundled with Creator 2.
There are a couple of options for getting around this.
Option 1 – Use Sun Java System Application Server Enterprise Edition 8.1 2005Q1
If you check out the “Features and Benefits” between Sun Java System Application Server Platform Edition (http://www.sun.com/software/products/appsrvr_pe/features.xml) and Enterprise Edition (http://www.sun.com/software/products/appsrvr_ee/features.xml), you'll notice the Enterprise Edition lists the following.
Integrated JDBC driver collection - Pre-integrated and certified - allowing you to quickly and easily connect your applications to corporate data sources.
So to fix the issue, you can always install SJSAS Enterprise Edition.
Option 2 – Use the jTDS SQLServer JDBC Driver
There is a sourceforge.net project called “jTDS” (http://jtds.sourceforge.net/). This is an open source JDBC driver for SQLServer. You can define a data source in Creator 2 for the jTDS driver and point the data source at your SQLServer database. To do this, follow the instructions in the tutorial “Creating Database Server Types and Data Sources”. When you setup the remote deploy to the SJSAS EE, you need to choose “Data Sources Configured Automatically by JSCreator”. The following diagram shows a snapshot of the dialog.
Creator will setup up the necessary data configurations on SJSAS PE so the Data Direct driver is used as the DataSource driver and the jTDS driver is used for the JDBC driver.
Lastly, you'll need to copy “Creator_install_dir/startup/samples/driveradapter.jar” into the “AppServer_install_dir/lib” directory.
There's a Creator forum discussion around this topic at http://swforum.sun.com/jive/thread.jspa?forumID=123&threadID=51299
Many thanks to Jerry Dunn for helping me work through this.
Cheers!
-David
Posted by David Botterill
( Feb 01 2006, 11:53:42 PM MST )
Permalink
|
|
Tuesday January 31, 2006 There were many enhancements between Creator 2 Early Access 2 and the final release in regard to portlet development. One such enhancement was to get closer to the goal of fully supporting JSR-168.
Background
In the first article in this series, I discussed how to get portlet preferences. This blog will show the portlet developer how to get “PortletConfig” and ultimately portlet initialization parameters (init-param). Again, let's refer to JSR-168 to see what it says about PortletConfig and portlet init-params. JSR-168 says,
“PLT.6.1 Initialization Parameters - The getInitParameterNames and getInitParameter methods of the PortletConfig interface return the initialization parameter names and values found in the portlet definition in the deployment descriptor. ”
According to JSR-168, the only way to get portlet initialization parameters is to go through the “PortletConfig” interface.
JSR-168 also states that the only way to get PortletConfig is through the “init” life cycle method.
”PLT.5.2.2 Initialization - The portlet container must initialize the portlet object by calling the init method of the Portlet interface with a unique (per portlet definition) object implementing the PortletConfig interface.”
Here's the major problem. Creator uses JavaServer Faces and thus the JavaServer Faces portlet adapter which implements the life cycle methods. This is a shortcoming in JSR-168 because the specification doesn't provide a standard way for a framework, like JavaServer Faces, to provide the PortletConfig to applications leveraging the framework. You'll see below how we decided to expose the PortletConfig through the JavaServer Faces portlet adapter.
I'd like to give a special thanks to Deepak Gothe, the Sun engineer responsible for implementing the PortletConfig exposure in the JavaServer Faces portlet adapter. Deepak accommodated this change just before we pushed out the final release of Creator 2.
One more background issue I should discuss. How does the JavaServer Faces portlet adapter compare with the open source version on java.net? The JavaServer Faces portlet adapter used in Creator 2 has many enhancements to support more of JSR-168 than the version on java.net like supporting modes, PortletConfig, etc. I'm not sure yet whether or not the version used by Creator 2 will be made available on java.net. Hopefully I'll have more info on that later.
Also, keep in mind that JSR-168 mentions two sets of initialization parameters, one set is at the portlet application scope and the other is at the portlet scope. The portlet application level init-params can be obtained through PortletContext. These are the init-params defined in the web.xml file. We will focus on the portlet init-params defined in the portlet.xml file.
Details
First, we must get to the JavaServer Faces ExternalContext. To do this you can either use the following code in the page bean.
FacesContext.getCurrentInstance().getExternalContext();
Or you can go through the session bean like the following.
getExternalContext();
Here's an example of how to access the portlet init-param “test” from the page-bean.
Map applicationMap = FacesContext.getCurrentInstance().getExternalContext().getApplicationMap();
if(null != applicationMap) {
PortletConfig config = (PortletConfig)applicationMap.get("javax.portlet.PortletConfig");
this.txtParam1.setText(config.getInitParameter("test"));
}
You'll see that the key is the property name “javax.portlet.PortletConfig”. This property is stored in the application map of the external context. To test this in Creator, from the project node, right-click and choose, “Edit Portlet Deployment Descriptor”. You'll see a dialog like the following.
Add an init-param with a name of “test” and a value of “Test Value”. Add a static text field to a portlet page and a button. Double-click on the button and add the source above that goes in the action method of the page bean like this.
public String button1_action() {
/**
* Get the portlet init-param
*/
Map applicationMap = FacesContext.getCurrentInstance().getExternalContext().getApplicationMap();
if(null != applicationMap) {
PortletConfig config = (PortletConfig)applicationMap.get("javax.portlet.PortletConfig");
this.txtParam1.setText(config.getInitParameter("test"));
}
return null;
}
When you run the portlet and press the button you should see the static text field with the value “Test Value”.
Cheers!
-David
Posted by David Botterill
( Jan 31 2006, 01:59:21 AM MST )
Permalink
|
|
Wednesday January 25, 2006
|
|
Monday January 02, 2006 I recently got involved helping a user with a problem concerning a “Drop Down List” component and a custom “OptionsList”. Vana, “yovana” on the Creator Forum created a custom “OptionsList” but had the problem where the selected item would not show up. I came up with a simplified example that showed the same problem and though I'd share the problem and solution with everyone knowing that sooner or later, someone else would stumble on this issue.
Problem Statement
You have a drop down list that you want to show items that don't come from a Creator data source. The items are of a custom type. When you select one of these items, you expect the selected item to show selected when it is selected in the drop down list.
Solution
First, lets start by setting up the web application. We do this by dropping a “Drop Down List” component on page1.
Next, we add an property to the session bean by right-clicking on “SessionBean1. Java” in the project navigator and choosing “add property”. In the property dialog, we set “name” to “options” and “Type” to “OptionsList”. Then we edit “SessionBean1.java” and add the following code to the constructor.
/**
* Construct a new session data bean instance.
*/
public SessionBean1() {
this.options = new MyOptionsList();
}
The class “MyOptionsList” looks like this:
package dropdownselect;
import com.sun.rave.web.ui.model.Option;
import com.sun.rave.web.ui.model.OptionsList;
/**
*
* @author David Botterill
*/
public class MyOptionsList extends OptionsList {
Option [] options = new Option[2];
/** Creates a new instance of MyOptionsList */
public MyOptionsList() {
Object [] values = new Object[2];
values[0] = "ID1";
values[1] = "David";
options[0] = new Option(new MyObject(values),"ID1");
values = new Object[2];
values[0] = "ID2";
values[1] = "Jim";
options[1] = new Option(new MyObject(values),"ID2");
this.setOptions(options);
}
}
If you're copy/pasting this code, be sure to change the package name accordingly.
Next, and most importantly, we need to define “MyObject”. Here is that class:
package dropdownselect;
/**
*
* @author David Botterill
*/
public class MyObject {
Object [] objArray;
/** Creates a new instance of MyObject */
public MyObject(Object [] inArray) {
objArray = inArray;
}
public String toString() {
String returnString = "";
for(int ii=0; null != objArray && ii < objArray.length; ii++) {
returnString += String.valueOf(objArray[ii]) + "\n";
}
return returnString;
}
public boolean equals(Object compareTo) {
String thisString = this.toString();
String compareToString = compareTo.toString();
if(thisString.equals(compareToString)) {
return true;
} else return false;
}
}
Two very important things to remember about “MyObject”.
Lastly, we need to bind the “Drop Down List” to “sessionBean1” “options”. We do this by selecting the “Drop Down List” on design view of “page1”, right-clicking and selecting “Property Bindings...”. The following figure shows the dialog that will appear. We then select SessionBean1->options=>options.
I hope this helps those of you hoping do make custom OptionsLists and custom Object types for those lists.
Cheers!
-David
Posted by David Botterill
( Jan 02 2006, 02:51:43 PM MST )
Permalink
|
|
Tuesday November 29, 2005 So to get to the topic, in setting up my machine for Java Studio Creator development, I ran into a problem installing the Sun Application Server Platform Edition (PE). Since Creator installs PE during its installation, you will see something during the installation complaining about missing libstdc++ libraries. Here's how to get around that.
/. /usr /usr/share /usr/share/doc /usr/share/doc/libstdc++5 /usr/share/doc/libstdc++5/copyright /usr/share/doc/libstdc++5/README.Debian /usr/share/doc/libstdc++5/changelog.Debian.gz /usr/lib /usr/lib/libstdc++.so.5.0.7 /usr/lib/libstdc++.so.5
apt-get update apt-get install libstdc++5
ln -s /usr/lib/libstdc++.so.5.0.7 /usr/lib/libstdc++-libc6.2-2.so.3
A special thanks to my team mate and fellow Linux head Marco Walther for helping me with this problem. Marco has Suse installed and was able to work out what symbolic links where needed.
Posted by David Botterill
( Nov 29 2005, 08:09:16 PM MST )
Permalink
Comments [8]
|
|
Friday October 07, 2005 So this is the first of hopefully several blogs on looking under the hood of portlet development in Java Studio Creator.
Background
Today I'll cover getting at portlet preferences. First, let's get some background information about preferences out of the way. JSR-168 says:
"Portlet preferences are intended to store basic configuration data for portlets. It is not the purpose of the portlet preferences to replace general purpose databases."
Most portal users would expect to click on the window decoration associated with "EDIT" to get to the settings for the portlet. JSR-168 also puts a restriction on when preferences can be changed. From JSR-168:
Portlets have access to the associated PortletPreferences object while they are processing requests. Portlets may only modify preferences attributes during a processAction invocation.
Details
Enough background, let's get to some code. As stated in JSR-168, you get to portlet preferences through a "PortletRequest". We can get to "PortletRequest" through "javax.faces.context.ExternalContext". Finally, we can get "javax.faces.context.ExternalContext" through the session bean created for each Creator portlet.
From the session bean, the code would look like this:
ExternalContext externalContext = this.getExternalContext();
PortletRequest request = (PortletRequest) externalContext.getRequest();
PortletPreferences portletPreferences = request.getPreferences();
From the page bean, the code would look like this:
ExternalContext externalContext = this.getSessionBean1().getExternalContext();
PortletRequest request = (PortletRequest) externalContext.getRequest();
PortletPreferences portletPreferences = request.getPreferences();
Gotchas
A logical approach would be to associate the portlet preferences with the session bean and let the session bean manage getting the preferences. This works fine for reading the preferences. If you want to save the preferences through "store", however, the Pluto implementation has a "gotcha". Pluto enforces the JSR-168 restriction Portlets may only modify preferences attributes during a processAction invocation. by checking what type of request you're in when you get the preferences. This means if you get the preferences from the session bean when you want to read values to fill in content, the Pluto implemented PortletPreferences record the fact that you got them through a render request. When you go to "store" the preferences, Pluto throws an IllegalStateException exception stating "store is only allowed inside a processAction call". One way around this would be to get the preferences just before you "store" and set the new preferences with values from the existing preferences. Please see the solution below.
Solution
Here's an example of how to manage preferences from a Creator portlet.
snip..
private PortletPreferenceAdapter portletPreferenceAdapter;
snip...
public void init() {
portletPreferenceAdapter = new PortletPreferenceAdapter(this);
}
snip...
public PortletPreferenceAdapter getPortletPreferenceAdapter() {
return portletPreferenceAdapter;
}
public ExternalContext getSessionContext() {
return this.getExternalContext();
}
import java.io.IOException;
import javax.faces.context.ExternalContext;
import javax.portlet.PortletPreferences;
import javax.portlet.PortletRequest;
import javax.portlet.ReadOnlyException;
import javax.portlet.ValidatorException;
/**
*
* @author David Botterill
*/
public class PortletPreferenceAdapter {
private PortletPreferences portletPreferences;
private SessionBean1 sessionBean;
/** Creates a new instance of MyPortletPreferences */
public PortletPreferenceAdapter(SessionBean1 inSessionBean) {
sessionBean = inSessionBean;
ExternalContext context = sessionBean.getSessionContext();
PortletRequest request = (PortletRequest) context.getRequest();
this.portletPreferences = request.getPreferences();
}
/**
* Getter for property name.
* @return Value of property name.
*/
public String getName() {
return (String) portletPreferences.getValue("name",null);
}
/**
* Setter for property name.
* @param name New value of property name.
*/
public void setName(String name) throws ReadOnlyException {
portletPreferences.setValue("name", name);
}
/**
* Getter for property phone.
* @return Value of property phone.
*/
public String getPhone() {
return (String) portletPreferences.getValue("phone",null);
}
/**
* Setter for property phone.
* @param phone New value of property phone.
*/
public void setPhone(String phone) throws ReadOnlyException {
portletPreferences.setValue("phone", phone);
}
public void save() throws ReadOnlyException, IOException, ValidatorException {
ExternalContext context = sessionBean.getSessionContext();
PortletRequest request = (PortletRequest) context.getRequest();
PortletPreferences storePreferences = request.getPreferences();
storePreferences.setValue("name", this.getName());
storePreferences.setValue("phone", this.getPhone());
storePreferences.store();
}
}
try {
this.getSessionBean1().getPortletPreferenceAdapter().setName((String)this.getTxtName().getText());
this.getSessionBean1().getPortletPreferenceAdapter().setPhone((String)this.getTxtPhone().getText());
this.getSessionBean1().getPortletPreferenceAdapter().save();
} catch(ReadOnlyException proe) {
log("Portlet ReadOnlyException=" + proe);
} catch(IOException ioe) {
log("IOException storing preferences=" + ioe);
} catch(ValidatorException ve) {
log("ValidatorException storing preferences=" + ve);
}
public void prerender() {
this.txtName.setValue(this.getSessionBean1().getPortletPreferenceAdapter().getName());
this.txtPhone.setValue(this.getSessionBean1().getPortletPreferenceAdapter().getPhone());
}
|
|
Friday September 23, 2005 In my last "blog":http://blogs.sun.com/roller/comments/david/Weblog/creator_2_ea_and_apache about Creator and Pluto, I briefly mentioned how erasing the “plutocontainer” directory in your user directory will reset Pluto.
Let me explain a little bit more about that. If for some reason, your portlet environment, Pluto, seems to be trashed and not working correctly when you deploy from Creator, you can delete the “plutocontainer” directory in your user directory to cause a refresh. The next time you deploy a portlet, the “plutocontainer” directory will be created again for you.
The “plutocontainer” directory is basically Pluto deployed. Now I know some of you will be tempted to experiment with changing things in this directory.
*CAUTION*: Please understand that when you do so, you're on your own. Also, I won't guarantee that this implementation will continue in the next release.
The great part is if you mess it up too bad, you simply have to rename it or delete it to get a fresh copy. When the “plutocontainer” directory is created, Creator basically extracts a jar from a jar then unjars it. That's why the “Initializing portlet container. Please wait...” period of a deploy can take so long.
Posted by David Botterill ( Sep 23 2005, 09:37:29 AM MDT ) Permalink Comments [0]
|
|