I love OSX Leopard, especially the spaces feature. It is really nice to have several "Spaces" with different apps open on each. However, I did find one nuance that is a bit annoying. If you open an application which allows for multiple windows (such as Firefox), you must use all of the windows within the same space. That means you cannot open Firefox in Space 1 and then go into Space 2 and open another FireFox window.
Now, there is an easy work around to this, and that is simply opening up all of your Firefox windows within the same Space and then hitting F8 to show all Spaces. Once you have all spaces showing then you can drag the windows into separate spaces as you wish. The issue I have found with this is that if you use the dock to navigate and hit the Firefox icon then spaces may go berserk. I have had spaces go back and forth between windows until I intervened with a mouse click.
This becomes frustrating if you are trying to use an technology such as Java Web Start in one Space and another Firefox window in a separate space. If the Web Start application tries to fire another window (such as a report), then Spaces will go berserk again.
Really, this is not a big issue but I thought I would point it out for anyone who was having issues with Spaces. The easiest work around in this case is to only use Firefox or other such apps within once Space only.
I am an application developer, database administrator, technical writer, and Java evangelist. Frequent this blog to learn from my experiences in Java, JavaEE, PL/SQL, and Python/Jython development. Follow my tweets @ http://twitter.com/javajuneau
Monday, November 19, 2007
Monday, November 05, 2007
OSX and JavaFX Script
Recently, there has been a ton of complaining that JDK6 has not been ported over to OSX 10.5 Leopard. I am a 10.4 Tiger user, and I am currently running Apple's Java 1.5 implementation. I like the Apple JDK 5 implementation...it looks much nicer than running Swing apps on Windows. However, I do hope that JDK 6 is available soon for OSX because I'd like to start using JavaFX within my Java programs on my Mac.
Without thinking twice, I downloaded Netbeans 6.0 Beta 2 and the JavaFX plugins on my Mac. I then started writing some FX code and calling it from native Java, and realized that I cannot code against the javax.script packages in JDK 5. I am now in need of JDK 6 to move forward with JavaFX on the Mac.
This blog post is just another posting regarding the desire for JDK 6 to be ported to OSX. I hope it comes soon...until then I am stuck with Windows for writing any JavaFX apps.
Without thinking twice, I downloaded Netbeans 6.0 Beta 2 and the JavaFX plugins on my Mac. I then started writing some FX code and calling it from native Java, and realized that I cannot code against the javax.script packages in JDK 5. I am now in need of JDK 6 to move forward with JavaFX on the Mac.
This blog post is just another posting regarding the desire for JDK 6 to be ported to OSX. I hope it comes soon...until then I am stuck with Windows for writing any JavaFX apps.
Wednesday, September 26, 2007
Jython Monthly - Call for Articles
After a long hiatus, the Jython Monthly newsletter will begin distribution again this October. If you have any content that you would like to post, please do so using this link. The October edition of Jython Monthly is scheduled for distribution on 10/9.
Thanks in advance for any article or tutorial submissions!
Thanks in advance for any article or tutorial submissions!
Wednesday, September 12, 2007
Migrating SEAM Applications from Glassfish V1 to Glassfish V2
I've come up with some simple steps for migrating a JBoss SEAM application from Glassfish V1 to Glassfish V2. Actually, you can configure all SEAM applications which you plan on deploying to Glassfish in this manner, and they will be deployable on either V1 or V2.
Keep in mind that I am also integrating Ajax4Jsf into my SEAM applications.
1) Update faces-config.xml (if needed) to ensure that you are using SeamFaceletViewHandler
<view-handler>org.jboss.seam.ui.facelet.SeamFaceletViewHandler</view-handler>
2) Update web.xml
- Add context-param for org.ajax4jsf.VIEW_HANDLERS
<context-param>
<param-name>org.ajax4jsf.VIEW_HANDLERS</param-name>
<param-value>org.jboss.seam.ui.facelet.SeamFaceletViewHandler</param-value>
</context-param>
- Add SUN Faces Listener
<listener>
<listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>
- If using Ajax4JSF, update the filter to include dispatchers
<filter-mapping>
<filter-name>ajax4jsf</filter-name>
<url-pattern>*.seam</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
3) Ensure that all database drivers are installed on the new server.
4) If using Ajax4Jsf, you will want to ensure that you are packaging Apache Commons 3.2
Keep in mind that I am also integrating Ajax4Jsf into my SEAM applications.
1) Update faces-config.xml (if needed) to ensure that you are using SeamFaceletViewHandler
<view-handler>org.jboss.seam.ui.facelet.SeamFaceletViewHandler</view-handler>
2) Update web.xml
- Add context-param for org.ajax4jsf.VIEW_HANDLERS
<context-param>
<param-name>org.ajax4jsf.VIEW_HANDLERS</param-name>
<param-value>org.jboss.seam.ui.facelet.SeamFaceletViewHandler</param-value>
</context-param>
- Add SUN Faces Listener
<listener>
<listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>
- If using Ajax4JSF, update the filter to include dispatchers
<filter-mapping>
<filter-name>ajax4jsf</filter-name>
<url-pattern>*.seam</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
3) Ensure that all database drivers are installed on the new server.
4) If using Ajax4Jsf, you will want to ensure that you are packaging Apache Commons 3.2
Friday, September 07, 2007
Creating RSS Reader Component Using SEAM and ROME
I've been working lately on an enterprise application which will be used for developing and maintaining an organization's website. The application is being written using JSF, JBoss SEAM 1.2.1 GA, Facelets, ROME, Ajax4Jsf, and deploying to Glassfish V1.
There was a requirement to have an RSS reader as well as the ability to create RSS feeds. I found that the Rome Project had all of the tools which I was going to require to make this function. It is a great RSS library, and if you code in Java and use RSS then I definitely recommend it.
I've created an RSS reader which uses an Oracle database back end to store a table of RSS feeds to parse. There is also a table of pages in the database, and each RSS feed record is tied to one or more of the pages. The RSS web page component can go on any page...as long as the page is registered in the database. An administrator then has the ability to add RSS feeds to be read on that page. The component uses AJAX to display a news title for 10 seconds, and then read the database and parse the next RSS entry in the feed. Once the component has read all of the entries for a particular feed, it looks for more feeds registered to that page. If it finds more then it will parse all entries within that feed and so on. In the end, the RSS reader is a component which simply displays news from one or more RSS feed sources using AJAX.
The Database
create table rss_feed as(
FEED_ID NUMBER,
CONTENT_PAGE_ID NUMBER,
FEED_URL VARCHAR2(1000),
FEED_NAME VARCHAR2(500));
alter table rss_feed
add constraint rss_feed_pk
primary key(feed_id);
create sequence rssapp_rss_feed_seq
start with 1
increment by 1;
(This assumes that you have a table which stores each page name along with a unique page id)
The Code
Since we are using EJB3 technology with the SEAM framework, we will require an Entity class for persistence. We also need an EJB session bean which will contain all of the RSS logic, along with a local interface.
Entity Class - Straight forward. I use Netbeans to create the initial class from the database, and then I add the SEAM annotations.
/*
* RssAppRssFeed.java
*/
package org.jj.entity;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
@Entity
@Scope(ScopeType.PAGE)
@Name("RssAppRssFeed")
@Table(name = "RSSAPP_RSS_FEED")
@NamedQueries( {
@NamedQuery(name = "RssAppRssFeed.findByFeedId", query = "SELECT f FROM RssAppRssFeed f WHERE f.feedId = :feedId"),
@NamedQuery(name = "RssAppRssFeed.findByContentPageId", query = "SELECT f FROM RssAppRssFeed f WHERE f.contentPageId = :contentPageId"),
@NamedQuery(name = "RssAppRssFeed.findByFeedUrl", query = "SELECT f FROM RssAppRssFeed f WHERE f.feedUrl = :feedUrl"),
@NamedQuery(name = "RssAppRssFeed.findByFeedName", query = "SELECT f FROM RssAppRssFeed f WHERE f.feedName = :feedName")
})
public class RssAppRssFeed implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE,
generator="RssApp_rss_feed_seq_generator")
@SequenceGenerator(name="RssApp_rss_feed_seq_generator",sequenceName="RssApp_rss_feed_seq", allocationSize=1)
@Column(name = "FEED_ID", nullable = false)
private BigDecimal feedId;
@Column(name = "CONTENT_PAGE_ID")
private BigInteger contentPageId;
@Column(name = "FEED_URL")
private String feedUrl;
@Column(name = "FEED_NAME")
private String feedName;
/** Creates a new instance of RssAppRssFeed */
public RssAppRssFeed() {
}
/**
* Creates a new instance of RssAppRssFeed with the specified values.
* @param feedId the feedId of the RssAppRssFeed
*/
public RssAppRssFeed(BigDecimal feedId) {
this.feedId = feedId;
}
/**
* Gets the feedId of this RssAppRssFeed.
* @return the feedId
*/
public BigDecimal getFeedId() {
return this.feedId;
}
/**
* Sets the feedId of this RssAppRssFeed to the specified value.
* @param feedId the new feedId
*/
public void setFeedId(BigDecimal feedId) {
this.feedId = feedId;
}
/**
* Gets the contentPageId of this RssAppRssFeed.
* @return the contentPageId
*/
public BigInteger getContentPageId() {
return this.contentPageId;
}
/**
* Sets the contentPageId of this RssAppRssFeed to the specified value.
* @param contentPageId the new contentPageId
*/
public void setContentPageId(BigInteger contentPageId) {
this.contentPageId = contentPageId;
}
/**
* Gets the feedUrl of this RssAppRssFeed.
* @return the feedUrl
*/
public String getFeedUrl() {
return this.feedUrl;
}
/**
* Sets the feedUrl of this RssAppRssFeed to the specified value.
* @param feedUrl the new feedUrl
*/
public void setFeedUrl(String feedUrl) {
this.feedUrl = feedUrl;
}
/**
* Gets the feedName of this RssAppRssFeed.
* @return the feedName
*/
public String getFeedName() {
return this.feedName;
}
/**
* Sets the feedName of this RssAppRssFeed to the specified value.
* @param feedName the new feedName
*/
public void setFeedName(String feedName) {
this.feedName = feedName;
}
/**
* Returns a hash code value for the object. This implementation computes
* a hash code value based on the id fields in this object.
* @return a hash code value for this object.
*/
@Override
public int hashCode() {
int hash = 0;
hash += (this.feedId != null ? this.feedId.hashCode() : 0);
return hash;
}
/**
* Determines whether another object is equal to this RssAppRssFeed. The result is
*
* has the same id field values as this object.
* @param object the reference object with which to compare
* @return
*
*/
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof RssAppRssFeed)) {
return false;
}
RssAppRssFeed other = (RssAppRssFeed)object;
if (this.feedId != other.feedId && (this.feedId == null || !this.feedId.equals(other.feedId))) return false;
return true;
}
/**
* Returns a string representation of the object. This implementation constructs
* that representation based on the id fields.
* @return a string representation of the object.
*/
@Override
public String toString() {
return "org.jj.entity.RssAppRssFeed[feedId=" + feedId + "]";
}
}
EJB Session Bean - Once again, I use Netbeans to generate the initial session bean from the entity class and I modify for SEAM. I then added all of the essential methods and logic for the RSS in working with ROME. You will notice that I did not use SEAM's @In @Out annotations on some of the variables...that is because I had issues when doing so. The code that I post here does work as expected. You will also see some doubleSubmitIndex variables...this is due to an issue I've seen with Ajax4Jsf. When I use the a4j:poll, the page seems to invoke the server method twice. It causes the RSS reader to skip entries within the feed. Therefore, I coded a work around which is kind of messy, but it works.
/*
* FeedReader.java
*/
package org.jj.beans;
import com.sun.net.ssl.SSLContext;
import com.sun.syndication.feed.synd.SyndEntryImpl;
import java.net.URL;
import java.io.InputStreamReader;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.SyndFeedInput;
import com.sun.syndication.io.XmlReader;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.ejb.Stateless;
import javax.interceptor.Interceptors;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.jj.entity.RssAppContentPage;
import org.jj.entity.RssAppRssFeed;
import org.jj.interfaces.FeedLocal;
import org.jj.utility.RssAppCommonTasks;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Destroy;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.datamodel.DataModel;
/**
*
*/
@Stateful
@Scope(ScopeType.SESSION)
@Name("rssReader")
@Interceptors({org.jboss.seam.ejb.SeamInterceptor.class})
public class FeedReader implements FeedLocal {
@PersistenceContext(unitName="rssApp-ejbPU-FESSPROD")
private EntityManager em;
@DataModel
public List feedList=null;
private List rssFeedList = null;
private String pageName = null;
@Out(required=false)
private Feed feedBean;
private String feedText = null;
private Date feedDate = null;
private String feedTitle = null;
private int feedCounter;
private int feedEntryCounter;
private int feedIndex;
private int feedEntryIndex;
private int doubleSubmitIndex;
private int doubleSubmitFeedIndex;
private Query qry;
public void readFeed() {
pageName = RssAppCommonTasks.obtainPageName();
if (!pageName.equals("underMaintenance")){
qry = em.createQuery("select object(p) from RssAppContentPage as p " +
"where p.contentPage = :pageName")
.setParameter("pageName", pageName);
RssAppContentPage page = (RssAppContentPage) qry.getSingleResult();
qry = em.createQuery("select object(f) from RssAppRssFeed as f " +
"where f.contentPageId = :pageId")
.setParameter("pageId", page.getContentPageId());
rssFeedList = qry.getResultList();
// Parse rss feeds for page, if any
if (rssFeedList.size() > 0){
for(int index = 0; index <= rssFeedList.size()-1; index++){ boolean ok = false; int entryNumber = 0; int entryIndex = 0; RssAppRssFeed rssFeed = new RssAppRssFeed(); rssFeed = rssFeedList.get(index); System.out.println("BEGINNING RSS READ....."); if (rssFeed.getFeedUrl() != null) { try { feedList = null; URL feedUrl = new URL(rssFeed.getFeedUrl()); SyndFeedInput input = new SyndFeedInput(); SyndFeed feed = input.build(new XmlReader(feedUrl)); entryNumber = feed.getEntries().size(); initializeList(); for (entryIndex = 0; entryIndex <= entryNumber; entryIndex++){ System.out.println("Reading..."); feedBean = new Feed(); feedBean.setAuthor(feed.getAuthor()); feedBean.setDescription(feed.getDescription()); feedBean.setEntry(((SyndEntryImpl)feed.getEntries().get(entryIndex)).getTitle()); feedBean.setEntryLink(((SyndEntryImpl)feed.getEntries().get(entryIndex)).getLink()); feedBean.setEntryUpdatedDate(((SyndEntryImpl)feed.getEntries().get(entryIndex)).getPublishedDate()); feedBean.setTitle(feed.getTitle()); feedBean.setUri(feed.getUri()); feedList.add(feedBean); } ok = true; } catch (Exception ex) { ex.printStackTrace(); System.out.println("ERROR: "+ex.getMessage()); } } if (!ok) { System.out.println(); System.out.println("FeedReader reads and prints any RSS/Atom feed type."); System.out.println("The first parameter must be the URL of the feed to read."); System.out.println(); } } } } } /** * This method is invoked via ajax from the front end page in order to read * a new feed into the display. The ajax front end causes a double submit * to this method, so we need to adjust counters such that they will only update * on every other submit. We do this by using the doubleSubmitIndex numbers. */ public void updateFeed(){ if (doubleSubmitIndex > 1){
doubleSubmitIndex = 0;
}
if (doubleSubmitFeedIndex > 1){
doubleSubmitFeedIndex = 0;
}
pageName = RssAppCommonTasks.obtainPageName();
if (!pageName.equals("underMaintenance")){
qry = em.createQuery("select object(p) from RssAppContentPage as p " +
"where p.contentPage = :pageName")
.setParameter("pageName", pageName);
RssAppContentPage page = (RssAppContentPage) qry.getSingleResult();
qry = em.createQuery("select object(f) from RssAppRssFeed as f " +
"where f.contentPageId = :pageId")
.setParameter("pageId", page.getContentPageId());
rssFeedList = qry.getResultList();
/*
* Obtain a list of rss feeds for a particular web page. If feeds
* exist for that page, then enter the feed parse logic.
*/
if (rssFeedList.size() > 0){
feedCounter = rssFeedList.size();
if(this.getFeedIndex() > feedCounter - 1){
this.setFeedIndex(0);
}
boolean ok = false;
int entryIndex = 0;
/*
* Obtain all feed entries for this particular feed index
*/
RssAppRssFeed rssFeed = new RssAppRssFeed();
RssFeed = rssFeedList.get(getFeedIndex());
System.out.println("Feed Index: " + getFeedIndex() + " Entry Index: " + getFeedEntryIndex());
if (rssFeed.getFeedUrl() != null) {
try {
feedList = null;
URL feedUrl = new URL(rssFeed.getFeedUrl());
String feedEntryDateText = null;
String feedEntryText = null;
String feedEntryUrl = null;
SyndFeedInput input = new SyndFeedInput();
SyndFeed feed = input.build(new XmlReader(feedUrl));
/*
* Obtain count of all feed entries
*/
feedEntryCounter = feed.getEntries().size();
initializeList();
if(getFeedEntryIndex() > 0){
if (getFeedEntryIndex() > feedEntryCounter - 1){
setFeedEntryIndex(0);
}
}
System.out.println("Reading...");
feedBean = new Feed();
feedBean.setAuthor(feed.getAuthor());
feedBean.setDescription(feed.getDescription());
feedBean.setEntry(((SyndEntryImpl)feed.getEntries().get(getFeedEntryIndex())).getTitle());
feedBean.setEntryLink(((SyndEntryImpl)feed.getEntries().get(getFeedEntryIndex())).getLink());
feedBean.setEntryUpdatedDate(((SyndEntryImpl)feed.getEntries().get(getFeedEntryIndex())).getPublishedDate());
feedBean.setTitle(feed.getTitle());
setFeedTitle(feed.getTitle());
feedBean.setUri(feed.getUri());
feedList.add(feedBean);
this.feedDate = feedBean.getEntryUpdatedDate();
feedText = "" +
feedBean.getEntry() + "";
ok = true;
if(doubleSubmitIndex > 0) {
this.feedEntryIndex++;
doubleSubmitIndex++;
// If all entries within current feedIndex have been read, move on
// to the next feed and start with entry zero.
if (feedEntryIndex > feedEntryCounter - 1){
this.feedIndex++;
this.feedEntryIndex = 0;
}
} else {
doubleSubmitIndex++;
}
} catch (Exception ex) {
ex.printStackTrace();
System.out.println("ERROR: "+ex.getMessage());
}
}
if (!ok) {
System.out.println();
System.out.println("FeedReader reads and prints any RSS/Atom feed type.");
System.out.println("The first parameter must be the URL of the feed to read.");
System.out.println();
}
}
}
}
private void initializeList(){
if (feedList == null){
feedList = new ArrayList();
}
}
public String getFeedText() {
return feedText;
}
public void setFeedText(String feedText) {
this.feedText = feedText;
}
public String getFeedTitle() {
return feedTitle;
}
public void setFeedTitle(String feedTitle) {
this.feedTitle = feedTitle;
}
public int getFeedIndex() {
return feedIndex;
}
public void setFeedIndex(int feedIndex) {
this.feedIndex = feedIndex;
}
public int getFeedEntryIndex() {
return feedEntryIndex;
}
public void setFeedEntryIndex(int feedEntryIndex) {
this.feedEntryIndex = feedEntryIndex;
}
public Date getFeedDate() {
return feedDate;
}
public void setFeedDate(Date feedDate) {
this.feedDate = feedDate;
}
@Remove @Destroy
public void destroy(){}
}
Local Interface - Nothing exciting in the local interface
/**
* FeedLocal.java
*/
package org.jj.interfaces;
import java.util.Date;
public interface FeedLocal {
void readFeed();
java.lang.String getFeedText();
void setFeedText(String feedText);
void updateFeed();
void destroy();
int getFeedIndex();
void setFeedIndex(int feedIndex);
Date getFeedDate();
void setFeedDate(Date feedDate);
java.lang.String getFeedTitle();
void setFeedTitle(String feedTitle);
}
Utility Class - Here is an excerpt from my utility class. This code obtains the current page name from the FacesContext.
public final class RssAppCommonTasks {
public static String obtainPageName(){
String currentPageName = null;
Query qry = null;
String tempPageName = FacesContext.getCurrentInstance().getViewRoot().getViewId();
if (tempPageName.lastIndexOf("/") > 0) {
tempPageName = tempPageName.substring(tempPageName.lastIndexOf("/") + 1).replace(".seam","").replace(".xhtml","");
currentPageName = tempPageName;
System.out.println("tempPageName: " + currentPageName);
} else {
System.out.println("view id: " + FacesContext.getCurrentInstance().getViewRoot().getViewId());
System.out.println("updated view id: " +
FacesContext.getCurrentInstance().getViewRoot().getViewId().replace("/","").replace(".seam","").replace(".xhtml",""));
currentPageName = FacesContext.getCurrentInstance().getViewRoot().getViewId().replace("/","").replace(".seam","").replace(".xhtml","");
}
return currentPageName;
}
***
}
pages.xml - Each page which contains the RSS component code will require an element within the pages.xml file to invoke server-side code.
<page id="/myPage.xhtml" action="#{rssReader.updateFeed}">
Component code in the XHTML page - I haven't yet created a separate component/tag for this code, but it should work by simply copying and pasting this code in each page which uses the reader. The back end code then determines which page is calling the code and parses the feeds in the database which are tied to that page.
<div id="autoreader">
<a4j:poll interval="10000"
reRender="autoReaderText, autoReaderDate, feedTitle"
action="#{rssReader.updateFeed}">
</a4j:poll>
<p align="center" class="sub_head_sub"><br />
<h:outputText id="feedTitle"
value="#{rssReader.feedTitle}"/>
</p>
<table id="feedList" name="feedList">
<td bgcolor="#CCFFCC" style="width: 100px">
<h:outputText id="autoReaderDate"
value="#{rssReader.feedDate}"/>
</td>
<td bgcolor="#CCFFCC" style="width: 400px">
<h:outputText id="autoReaderText"
escape="false"
value="#{rssReader.feedText}"/>
</td>
</table>
</div>
That is all there is to it. There is a bit of code to write, but the end result is very appealing. Once complete, one can add or remove feeds from the database and have them automatically appear on the desired pages.
There was a requirement to have an RSS reader as well as the ability to create RSS feeds. I found that the Rome Project had all of the tools which I was going to require to make this function. It is a great RSS library, and if you code in Java and use RSS then I definitely recommend it.
I've created an RSS reader which uses an Oracle database back end to store a table of RSS feeds to parse. There is also a table of pages in the database, and each RSS feed record is tied to one or more of the pages. The RSS web page component can go on any page...as long as the page is registered in the database. An administrator then has the ability to add RSS feeds to be read on that page. The component uses AJAX to display a news title for 10 seconds, and then read the database and parse the next RSS entry in the feed. Once the component has read all of the entries for a particular feed, it looks for more feeds registered to that page. If it finds more then it will parse all entries within that feed and so on. In the end, the RSS reader is a component which simply displays news from one or more RSS feed sources using AJAX.
The Database
create table rss_feed as(
FEED_ID NUMBER,
CONTENT_PAGE_ID NUMBER,
FEED_URL VARCHAR2(1000),
FEED_NAME VARCHAR2(500));
alter table rss_feed
add constraint rss_feed_pk
primary key(feed_id);
create sequence rssapp_rss_feed_seq
start with 1
increment by 1;
(This assumes that you have a table which stores each page name along with a unique page id)
The Code
Since we are using EJB3 technology with the SEAM framework, we will require an Entity class for persistence. We also need an EJB session bean which will contain all of the RSS logic, along with a local interface.
Entity Class - Straight forward. I use Netbeans to create the initial class from the database, and then I add the SEAM annotations.
/*
* RssAppRssFeed.java
*/
package org.jj.entity;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
@Entity
@Scope(ScopeType.PAGE)
@Name("RssAppRssFeed")
@Table(name = "RSSAPP_RSS_FEED")
@NamedQueries( {
@NamedQuery(name = "RssAppRssFeed.findByFeedId", query = "SELECT f FROM RssAppRssFeed f WHERE f.feedId = :feedId"),
@NamedQuery(name = "RssAppRssFeed.findByContentPageId", query = "SELECT f FROM RssAppRssFeed f WHERE f.contentPageId = :contentPageId"),
@NamedQuery(name = "RssAppRssFeed.findByFeedUrl", query = "SELECT f FROM RssAppRssFeed f WHERE f.feedUrl = :feedUrl"),
@NamedQuery(name = "RssAppRssFeed.findByFeedName", query = "SELECT f FROM RssAppRssFeed f WHERE f.feedName = :feedName")
})
public class RssAppRssFeed implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE,
generator="RssApp_rss_feed_seq_generator")
@SequenceGenerator(name="RssApp_rss_feed_seq_generator",sequenceName="RssApp_rss_feed_seq", allocationSize=1)
@Column(name = "FEED_ID", nullable = false)
private BigDecimal feedId;
@Column(name = "CONTENT_PAGE_ID")
private BigInteger contentPageId;
@Column(name = "FEED_URL")
private String feedUrl;
@Column(name = "FEED_NAME")
private String feedName;
/** Creates a new instance of RssAppRssFeed */
public RssAppRssFeed() {
}
/**
* Creates a new instance of RssAppRssFeed with the specified values.
* @param feedId the feedId of the RssAppRssFeed
*/
public RssAppRssFeed(BigDecimal feedId) {
this.feedId = feedId;
}
/**
* Gets the feedId of this RssAppRssFeed.
* @return the feedId
*/
public BigDecimal getFeedId() {
return this.feedId;
}
/**
* Sets the feedId of this RssAppRssFeed to the specified value.
* @param feedId the new feedId
*/
public void setFeedId(BigDecimal feedId) {
this.feedId = feedId;
}
/**
* Gets the contentPageId of this RssAppRssFeed.
* @return the contentPageId
*/
public BigInteger getContentPageId() {
return this.contentPageId;
}
/**
* Sets the contentPageId of this RssAppRssFeed to the specified value.
* @param contentPageId the new contentPageId
*/
public void setContentPageId(BigInteger contentPageId) {
this.contentPageId = contentPageId;
}
/**
* Gets the feedUrl of this RssAppRssFeed.
* @return the feedUrl
*/
public String getFeedUrl() {
return this.feedUrl;
}
/**
* Sets the feedUrl of this RssAppRssFeed to the specified value.
* @param feedUrl the new feedUrl
*/
public void setFeedUrl(String feedUrl) {
this.feedUrl = feedUrl;
}
/**
* Gets the feedName of this RssAppRssFeed.
* @return the feedName
*/
public String getFeedName() {
return this.feedName;
}
/**
* Sets the feedName of this RssAppRssFeed to the specified value.
* @param feedName the new feedName
*/
public void setFeedName(String feedName) {
this.feedName = feedName;
}
/**
* Returns a hash code value for the object. This implementation computes
* a hash code value based on the id fields in this object.
* @return a hash code value for this object.
*/
@Override
public int hashCode() {
int hash = 0;
hash += (this.feedId != null ? this.feedId.hashCode() : 0);
return hash;
}
/**
* Determines whether another object is equal to this RssAppRssFeed. The result is
*
true
if and only if the argument is not null and is a RssAppRssFeed object that* has the same id field values as this object.
* @param object the reference object with which to compare
* @return
true
if this object is the same as the argument;*
false
otherwise.*/
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof RssAppRssFeed)) {
return false;
}
RssAppRssFeed other = (RssAppRssFeed)object;
if (this.feedId != other.feedId && (this.feedId == null || !this.feedId.equals(other.feedId))) return false;
return true;
}
/**
* Returns a string representation of the object. This implementation constructs
* that representation based on the id fields.
* @return a string representation of the object.
*/
@Override
public String toString() {
return "org.jj.entity.RssAppRssFeed[feedId=" + feedId + "]";
}
}
EJB Session Bean - Once again, I use Netbeans to generate the initial session bean from the entity class and I modify for SEAM. I then added all of the essential methods and logic for the RSS in working with ROME. You will notice that I did not use SEAM's @In @Out annotations on some of the variables...that is because I had issues when doing so. The code that I post here does work as expected. You will also see some doubleSubmitIndex variables...this is due to an issue I've seen with Ajax4Jsf. When I use the a4j:poll, the page seems to invoke the server method twice. It causes the RSS reader to skip entries within the feed. Therefore, I coded a work around which is kind of messy, but it works.
/*
* FeedReader.java
*/
package org.jj.beans;
import com.sun.net.ssl.SSLContext;
import com.sun.syndication.feed.synd.SyndEntryImpl;
import java.net.URL;
import java.io.InputStreamReader;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.SyndFeedInput;
import com.sun.syndication.io.XmlReader;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.ejb.Stateless;
import javax.interceptor.Interceptors;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.jj.entity.RssAppContentPage;
import org.jj.entity.RssAppRssFeed;
import org.jj.interfaces.FeedLocal;
import org.jj.utility.RssAppCommonTasks;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Destroy;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.datamodel.DataModel;
/**
*
*/
@Stateful
@Scope(ScopeType.SESSION)
@Name("rssReader")
@Interceptors({org.jboss.seam.ejb.SeamInterceptor.class})
public class FeedReader implements FeedLocal {
@PersistenceContext(unitName="rssApp-ejbPU-FESSPROD")
private EntityManager em;
@DataModel
public List
private List
private String pageName = null;
@Out(required=false)
private Feed feedBean;
private String feedText = null;
private Date feedDate = null;
private String feedTitle = null;
private int feedCounter;
private int feedEntryCounter;
private int feedIndex;
private int feedEntryIndex;
private int doubleSubmitIndex;
private int doubleSubmitFeedIndex;
private Query qry;
public void readFeed() {
pageName = RssAppCommonTasks.obtainPageName();
if (!pageName.equals("underMaintenance")){
qry = em.createQuery("select object(p) from RssAppContentPage as p " +
"where p.contentPage = :pageName")
.setParameter("pageName", pageName);
RssAppContentPage page = (RssAppContentPage) qry.getSingleResult();
qry = em.createQuery("select object(f) from RssAppRssFeed as f " +
"where f.contentPageId = :pageId")
.setParameter("pageId", page.getContentPageId());
rssFeedList = qry.getResultList();
// Parse rss feeds for page, if any
if (rssFeedList.size() > 0){
for(int index = 0; index <= rssFeedList.size()-1; index++){ boolean ok = false; int entryNumber = 0; int entryIndex = 0; RssAppRssFeed rssFeed = new RssAppRssFeed(); rssFeed = rssFeedList.get(index); System.out.println("BEGINNING RSS READ....."); if (rssFeed.getFeedUrl() != null) { try { feedList = null; URL feedUrl = new URL(rssFeed.getFeedUrl()); SyndFeedInput input = new SyndFeedInput(); SyndFeed feed = input.build(new XmlReader(feedUrl)); entryNumber = feed.getEntries().size(); initializeList(); for (entryIndex = 0; entryIndex <= entryNumber; entryIndex++){ System.out.println("Reading..."); feedBean = new Feed(); feedBean.setAuthor(feed.getAuthor()); feedBean.setDescription(feed.getDescription()); feedBean.setEntry(((SyndEntryImpl)feed.getEntries().get(entryIndex)).getTitle()); feedBean.setEntryLink(((SyndEntryImpl)feed.getEntries().get(entryIndex)).getLink()); feedBean.setEntryUpdatedDate(((SyndEntryImpl)feed.getEntries().get(entryIndex)).getPublishedDate()); feedBean.setTitle(feed.getTitle()); feedBean.setUri(feed.getUri()); feedList.add(feedBean); } ok = true; } catch (Exception ex) { ex.printStackTrace(); System.out.println("ERROR: "+ex.getMessage()); } } if (!ok) { System.out.println(); System.out.println("FeedReader reads and prints any RSS/Atom feed type."); System.out.println("The first parameter must be the URL of the feed to read."); System.out.println(); } } } } } /** * This method is invoked via ajax from the front end page in order to read * a new feed into the display. The ajax front end causes a double submit * to this method, so we need to adjust counters such that they will only update * on every other submit. We do this by using the doubleSubmitIndex numbers. */ public void updateFeed(){ if (doubleSubmitIndex > 1){
doubleSubmitIndex = 0;
}
if (doubleSubmitFeedIndex > 1){
doubleSubmitFeedIndex = 0;
}
pageName = RssAppCommonTasks.obtainPageName();
if (!pageName.equals("underMaintenance")){
qry = em.createQuery("select object(p) from RssAppContentPage as p " +
"where p.contentPage = :pageName")
.setParameter("pageName", pageName);
RssAppContentPage page = (RssAppContentPage) qry.getSingleResult();
qry = em.createQuery("select object(f) from RssAppRssFeed as f " +
"where f.contentPageId = :pageId")
.setParameter("pageId", page.getContentPageId());
rssFeedList = qry.getResultList();
/*
* Obtain a list of rss feeds for a particular web page. If feeds
* exist for that page, then enter the feed parse logic.
*/
if (rssFeedList.size() > 0){
feedCounter = rssFeedList.size();
if(this.getFeedIndex() > feedCounter - 1){
this.setFeedIndex(0);
}
boolean ok = false;
int entryIndex = 0;
/*
* Obtain all feed entries for this particular feed index
*/
RssAppRssFeed rssFeed = new RssAppRssFeed();
RssFeed = rssFeedList.get(getFeedIndex());
System.out.println("Feed Index: " + getFeedIndex() + " Entry Index: " + getFeedEntryIndex());
if (rssFeed.getFeedUrl() != null) {
try {
feedList = null;
URL feedUrl = new URL(rssFeed.getFeedUrl());
String feedEntryDateText = null;
String feedEntryText = null;
String feedEntryUrl = null;
SyndFeedInput input = new SyndFeedInput();
SyndFeed feed = input.build(new XmlReader(feedUrl));
/*
* Obtain count of all feed entries
*/
feedEntryCounter = feed.getEntries().size();
initializeList();
if(getFeedEntryIndex() > 0){
if (getFeedEntryIndex() > feedEntryCounter - 1){
setFeedEntryIndex(0);
}
}
System.out.println("Reading...");
feedBean = new Feed();
feedBean.setAuthor(feed.getAuthor());
feedBean.setDescription(feed.getDescription());
feedBean.setEntry(((SyndEntryImpl)feed.getEntries().get(getFeedEntryIndex())).getTitle());
feedBean.setEntryLink(((SyndEntryImpl)feed.getEntries().get(getFeedEntryIndex())).getLink());
feedBean.setEntryUpdatedDate(((SyndEntryImpl)feed.getEntries().get(getFeedEntryIndex())).getPublishedDate());
feedBean.setTitle(feed.getTitle());
setFeedTitle(feed.getTitle());
feedBean.setUri(feed.getUri());
feedList.add(feedBean);
this.feedDate = feedBean.getEntryUpdatedDate();
feedText = "" +
feedBean.getEntry() + "";
ok = true;
if(doubleSubmitIndex > 0) {
this.feedEntryIndex++;
doubleSubmitIndex++;
// If all entries within current feedIndex have been read, move on
// to the next feed and start with entry zero.
if (feedEntryIndex > feedEntryCounter - 1){
this.feedIndex++;
this.feedEntryIndex = 0;
}
} else {
doubleSubmitIndex++;
}
} catch (Exception ex) {
ex.printStackTrace();
System.out.println("ERROR: "+ex.getMessage());
}
}
if (!ok) {
System.out.println();
System.out.println("FeedReader reads and prints any RSS/Atom feed type.");
System.out.println("The first parameter must be the URL of the feed to read.");
System.out.println();
}
}
}
}
private void initializeList(){
if (feedList == null){
feedList = new ArrayList();
}
}
public String getFeedText() {
return feedText;
}
public void setFeedText(String feedText) {
this.feedText = feedText;
}
public String getFeedTitle() {
return feedTitle;
}
public void setFeedTitle(String feedTitle) {
this.feedTitle = feedTitle;
}
public int getFeedIndex() {
return feedIndex;
}
public void setFeedIndex(int feedIndex) {
this.feedIndex = feedIndex;
}
public int getFeedEntryIndex() {
return feedEntryIndex;
}
public void setFeedEntryIndex(int feedEntryIndex) {
this.feedEntryIndex = feedEntryIndex;
}
public Date getFeedDate() {
return feedDate;
}
public void setFeedDate(Date feedDate) {
this.feedDate = feedDate;
}
@Remove @Destroy
public void destroy(){}
}
Local Interface - Nothing exciting in the local interface
/**
* FeedLocal.java
*/
package org.jj.interfaces;
import java.util.Date;
public interface FeedLocal {
void readFeed();
java.lang.String getFeedText();
void setFeedText(String feedText);
void updateFeed();
void destroy();
int getFeedIndex();
void setFeedIndex(int feedIndex);
Date getFeedDate();
void setFeedDate(Date feedDate);
java.lang.String getFeedTitle();
void setFeedTitle(String feedTitle);
}
Utility Class - Here is an excerpt from my utility class. This code obtains the current page name from the FacesContext.
public final class RssAppCommonTasks {
public static String obtainPageName(){
String currentPageName = null;
Query qry = null;
String tempPageName = FacesContext.getCurrentInstance().getViewRoot().getViewId();
if (tempPageName.lastIndexOf("/") > 0) {
tempPageName = tempPageName.substring(tempPageName.lastIndexOf("/") + 1).replace(".seam","").replace(".xhtml","");
currentPageName = tempPageName;
System.out.println("tempPageName: " + currentPageName);
} else {
System.out.println("view id: " + FacesContext.getCurrentInstance().getViewRoot().getViewId());
System.out.println("updated view id: " +
FacesContext.getCurrentInstance().getViewRoot().getViewId().replace("/","").replace(".seam","").replace(".xhtml",""));
currentPageName = FacesContext.getCurrentInstance().getViewRoot().getViewId().replace("/","").replace(".seam","").replace(".xhtml","");
}
return currentPageName;
}
***
}
pages.xml - Each page which contains the RSS component code will require an element within the pages.xml file to invoke server-side code.
<page id="/myPage.xhtml" action="#{rssReader.updateFeed}">
Component code in the XHTML page - I haven't yet created a separate component/tag for this code, but it should work by simply copying and pasting this code in each page which uses the reader. The back end code then determines which page is calling the code and parses the feeds in the database which are tied to that page.
<div id="autoreader">
<a4j:poll interval="10000"
reRender="autoReaderText, autoReaderDate, feedTitle"
action="#{rssReader.updateFeed}">
</a4j:poll>
<p align="center" class="sub_head_sub"><br />
<h:outputText id="feedTitle"
value="#{rssReader.feedTitle}"/>
</p>
<table id="feedList" name="feedList">
<td bgcolor="#CCFFCC" style="width: 100px">
<h:outputText id="autoReaderDate"
value="#{rssReader.feedDate}"/>
</td>
<td bgcolor="#CCFFCC" style="width: 400px">
<h:outputText id="autoReaderText"
escape="false"
value="#{rssReader.feedText}"/>
</td>
</table>
</div>
That is all there is to it. There is a bit of code to write, but the end result is very appealing. Once complete, one can add or remove feeds from the database and have them automatically appear on the desired pages.
Thursday, August 30, 2007
Oracle Database 11g
I'm really excited about the release of Oracle database 11g...even if it is only for Linux at this time. I am almost thinking about setting up a Linux box just to try it out...but perhaps I'll wait for the release of the Windows version.
There are a significant number of new features added to this release. One of the top items that I am interested in is "hot patching". I'm also glad that PL/SQL performance has been improved, and that SQL Tuning can now be fully automated.
Check out this link for a great amount of detail. The latest edition of Oracle magazine also showcases the new release...grab a copy if you do not have one yet.
This looks to be a release that we will definitely want to invest some time into!
There are a significant number of new features added to this release. One of the top items that I am interested in is "hot patching". I'm also glad that PL/SQL performance has been improved, and that SQL Tuning can now be fully automated.
Check out this link for a great amount of detail. The latest edition of Oracle magazine also showcases the new release...grab a copy if you do not have one yet.
This looks to be a release that we will definitely want to invest some time into!
Thursday, July 12, 2007
JBoss Seam Configurations - JARs and Details
I've sucessfully implemented NetBeans 6.0 M10 and Netbeans 5.5.1 projects using the JBOSS Seam framework. I can successfully deploy these projects to both Glassfish V1, JBoss 4.2.0, and JBoss 4.1. This blog post is a log so that I can remember the specific JAR files and details required for each of these projects. I intend to add onto this blog as time goes on and I encounter more detailed information.
Seam 1.2.1 GA and Glassfish V1:
This project utilizes the Ajax4Jsf and RichFaces APIs. I have been unable to make this setup work with Glassfish V2 as yet. If you have figured that one out, please let me know.
Follow these steps in either NB 5.5.1 or NB 6.0 M10
1) Create new Enterprise Application, and also create the following libraries within the IDE:
Seam1.2.1-GlassfishV1
hibernate-all.jar
hibernate-annotations.jar
jboss-common.jar
jboss-seam-debug.jar
jboss-seam-pdf.jar
jboss-seam-ui.jar
jboss-seam.jar
thirdparty-all.jar
jbpm-3.1.2.jar (If you plan to use JBpm...I have not tested as yet)
Ajax4Jsf
ajax4jsf-1.1.1.jar
commons-collections.jar
oscache-2.3.2.jar
richfaces-3.0.1.jar
2) Add those two libraries to your ejb sub-project along with these others:
commons-beanutils-1.7.0.jar
commons-codec-1.3.jar
commons-digester-1.6.jar
jboss-archive-browsing.jar
jsf-facelets.jar (unless you intend to add facelets support via the ide)
3) Add the following JARs to your war sub-project:
dom4j.jar (may not need this one...)
jboss-seam-ui.jar
4) Add configuration files to your ejb sub-project:
a) Add ejb-jar.xml to src/conf
b) Create empty seam.properties within src/conf
c) Create log4j.xml within src/conf
- Easiest configuration is to copy one of the log4j.xml files contained in the
example projects within the Seam 1.2.1 GA download.
d) Create persistence.xml within src/conf
- Use NetBeans to create persistence unit by right-clicking on the ejb sub-project
and then selecting New->Persistence Unit. Follow directions to create a unit
based upon one of the existing database connections you have defined in the IDE.
I use Toplink by default, but Hibernate works just as well.
5) Add configuration files to your war sub-project
a) Configure web.xml and faces-config.xml as suggested in Carol McDonald's Blog or Brian Leonard's Blog. It is also a good idea to take a look at the web.xml file from within one of the sample projects which comes with your Seam download. You will require a Seam filter, and Ajax4Jsf context-parameter if you plan to use that technology. I almost always use the same configuration contained within the sample project web.xml files, but also add the ejb references as discussed in the blog posts above.
b) Make sure the following additional xml files reside within your WEB-INF directory:
components.xml - Copy and use the one from the glassfish example in your Seam download. You will need to update it according to your ejb project name.
c) You may need to add META-INF to root of web pages and place application.xml within it.
I'll add the other configurations as time goes on, but this one will get you started with Seam application development on Glassfish V1.
Friday, July 06, 2007
Seam 2.0 and Netbeans 6.0 M10
Seam 2.0 works with Netbeans 6.0 M10 and the Netbeans Seam plugin. I've spent some time preparing an application based upon some of the examples given in the Seam 2.0 documentation.
I've managed to deploy and successfully run an application on JBoss 4.2.0 using Netbeans 6.0 M10 and the seam plugin. I only used the plug-in to generate the initial application. I did not use any of the other plug-in automation.
I've managed to deploy and successfully run an application on JBoss 4.2.0 using Netbeans 6.0 M10 and the seam plugin. I only used the plug-in to generate the initial application. I did not use any of the other plug-in automation.
Monday, July 02, 2007
Saw It, Got It, Using It
Netbeans 6.0 M10 is now available to the community. There are quite a few enhancements in this milestone.
I'll blog more about the M10 release as needed as time goes on. I've been using it all day with the Netbeans Seam plugin and Facelets plugin...and haven't experienced any issues thus far.
I'll blog more about the M10 release as needed as time goes on. I've been using it all day with the Netbeans Seam plugin and Facelets plugin...and haven't experienced any issues thus far.
Friday, June 29, 2007
JBoss Seam + Netbeans Update 2
The good news is that the Seam plugin for Netbeans deploys without any issues to JBoss 4.0.5 server. I've also added a Postgresql database into the mix and successfully generated entity classes and deployed to 4.0.5 successfully!
The bad news is that I ran into an issue with M9. At least, it is an issue with M9 and the Facelets plugin (on my workstation). I cannot tell if this issue is a bug with M9, or just my slow workstation, but the IDE literally locks up if I try to edit XHTML files with the Facelets plugin installed. I just found this out this morning when trying to add a new Facelets page to my Seam Plugin app. It would not work...I restarted the M9 application several times.
Needless to say, I've reverted to Netbeans 5.5.1 and have been using the Facelets code without issue.
In summary: Netbeans 5.5.1, Seam Framework Plugin, Facelets Plugin, and Postgresql database create an easy CRUD application without issue...and in just a few minutes!
As stated in previous posts, I will try to make a mini-application using this model. I then wish to port it to Glassfish as well just to see how difficult that step will be. It may take me a while...but I will post my results.
The bad news is that I ran into an issue with M9. At least, it is an issue with M9 and the Facelets plugin (on my workstation). I cannot tell if this issue is a bug with M9, or just my slow workstation, but the IDE literally locks up if I try to edit XHTML files with the Facelets plugin installed. I just found this out this morning when trying to add a new Facelets page to my Seam Plugin app. It would not work...I restarted the M9 application several times.
Needless to say, I've reverted to Netbeans 5.5.1 and have been using the Facelets code without issue.
In summary: Netbeans 5.5.1, Seam Framework Plugin, Facelets Plugin, and Postgresql database create an easy CRUD application without issue...and in just a few minutes!
As stated in previous posts, I will try to make a mini-application using this model. I then wish to port it to Glassfish as well just to see how difficult that step will be. It may take me a while...but I will post my results.
Saturday, June 23, 2007
JBoss Seam + Netbeans 6.0 M9 Update
I've not had much time lately to play with Seam and get some good development going. However, I've been trying to make the Seam plugin work with Netbeans 6.0 M9...and it does quite nicely. Follow the link to the blog by Michael Yuanto see how you should set up your environment. This is tested and functional with Netbeans 6.0 M9.
I tried to make this work with JBoss 4.2, but I never quite made it. The issue is that I need to run JBoss on a different port other than the default 8080. I cannot make this happen with JBoss 4.2 within the Netbeans 6.0 M9 environment. When I register the server with Netbeans, it automatically defaults to 8080...I do not like this. I've also tried to change all references to 8080 within the JBoss 4.2 home to something else...no luck. The good thing is that with JBoss 4.0.5, you can simply adjust the server.xml within the server\default\deploy\jbossweb-tomcat55.sar directory. This then registers with Netbeans 6.0 on the specified port without issue.
I am hopeful to hear more about the Netbeans Seam plugin soon...the initial release is very good...
I tried to make this work with JBoss 4.2, but I never quite made it. The issue is that I need to run JBoss on a different port other than the default 8080. I cannot make this happen with JBoss 4.2 within the Netbeans 6.0 M9 environment. When I register the server with Netbeans, it automatically defaults to 8080...I do not like this. I've also tried to change all references to 8080 within the JBoss 4.2 home to something else...no luck. The good thing is that with JBoss 4.0.5, you can simply adjust the server.xml within the server\default\deploy\jbossweb-tomcat55.sar directory. This then registers with Netbeans 6.0 on the specified port without issue.
I am hopeful to hear more about the Netbeans Seam plugin soon...the initial release is very good...
Saturday, June 09, 2007
JBoss SEAM 1.2.1 GA and Glassfish V2
I've just followed the excellent write-up by Roger Kitain and built the glassfish example for Seam on Glassfish v2. If you follow Roger's blog instructions, it works without any issues using Seam 1.2.1 GA.
Now...onto the Netbeans 6.0 M9 integration. I hope to install the Seam plug-in (or minimally the Facelets plug-in) for Netbeans to M9 and deploy to Glassfish...I'll blog on my results.
Now...onto the Netbeans 6.0 M9 integration. I hope to install the Seam plug-in (or minimally the Facelets plug-in) for Netbeans to M9 and deploy to Glassfish...I'll blog on my results.
Friday, June 08, 2007
Netbeans 6.0 - Great Information Resource
I am a little bit behind...but I've just recently read the article in the Netbeans Magazine May 2007 edition regarding Netbeans 6.0. It is an excellent article. If you are looking for a good resource to learn the newest features of the IDE then I definitely recommend giving it a read!
Also, another excellent resource is always Roumen's Weblog. I listen to each of the Netbeans podcasts, and I visit his site often...always has great information regarding Netbeans. He also has some good Flash Demos available.
Check it out Netbeans users!
Also, another excellent resource is always Roumen's Weblog. I listen to each of the Netbeans podcasts, and I visit his site often...always has great information regarding Netbeans. He also has some good Flash Demos available.
Check it out Netbeans users!
Tuesday, May 29, 2007
Good Java Reference
Just wanted to post the link to a good Java reference I ran across today. This may be old, but it is still a good reference while trying to port applications to different platforms. Read How to avoid pitfalls in your Java application development for some quick, yet decent material.
JFXBuilder...I'm Impressed
You've heard of JavaFX, right? Of course you have...unless you have not paid any attention to the Java world in the past couple of months. I'm interested in the upcoming technology and all that it will cover. I've read through a few tutorials and played around a bit and I do like the syntax of the FX scripting language. I was impressed when I checked out java.net this morning and saw that ReportMill has already released a WYSIWYG editor for JavaFX. I took a brief trial run and it looks good so far! Give it a test run at http://www.reportmill.com/jfx/ and you will also be impressed!
Wednesday, May 16, 2007
Two Early Access IDE Releases
Just recently, two of the IDEs which I use on a daily basis have released early preview distributions of future products. No doubt, JavaOne had a lot to do with the timing of these releases. I've used both of the new releases, but I cannot say that I will be using either of them full time as yet.
JDeveloper 11g - Quick Review
The technical preview for JDeveloper 11g was released recently. I decided to download it and take a look at it's capabilities this week. I must admit that I was blown away by the new layout of the IDE altogether. It is well thought out with added search boxes located throughout to assist in finding code. The application menu now displays only one application at a time by default...the other applications are listed in a pull-down menu. The overall look and feel is more visually appealing. I use the database connections features quite often and it is slick. Each database connection now has added options such as access to different types and database links. Another nice feature of the database connection editors is the SQL editor which opens by default when you connect to a database.
However, the JDeveloper 11g technical preview does have some faults. Unfortunately, the faults will limit my exposure to the IDE until the bugs have been repaired. For instance, the database connections expansion tree is way too sensitive. It is hard to select a database package and/or body for editing. By default, when you select a database package or package body then it opens in a read-only mode. You must select a variable, function, or procedure definition in order to edit the package. This is too cumbersome for my liking. I hope that these changes can be made for the next release because I can definitely see the potential in this IDE.
Netbeans 6.0 M9 - Quick Review
The Milestone 9 release of Netbeans 6.0 has an abundance of new features to tout. I have only performed some basic editing and development tasks thus far. Therefore, I do not feel that I can give an informative review of this release. However, with my limited exposure this IDE milestone release is outstanding. I have not run into any bugs thus far. The editor reacts nicely and the new look and feel is great. Built-in profiler is a welcome feature as well.
The only disappointing feature of M9 that I have found so far is that it does not come fully equipped with Tomcat AS. You must download and install Tomcat separately if you wish to use that application server. M9 comes with Glassfish by default (which is nice), but I think many people are still using Tomcat and may not like the removal.
It has been a great month for the Java community! Check out the IDEs when you have a chance because both of them are worthy of a look or two.
http://www.oracle.com/technology/software/products/jdev/index.html
http://www.netbeans.org/community/releases/60/index.html
JDeveloper 11g - Quick Review
The technical preview for JDeveloper 11g was released recently. I decided to download it and take a look at it's capabilities this week. I must admit that I was blown away by the new layout of the IDE altogether. It is well thought out with added search boxes located throughout to assist in finding code. The application menu now displays only one application at a time by default...the other applications are listed in a pull-down menu. The overall look and feel is more visually appealing. I use the database connections features quite often and it is slick. Each database connection now has added options such as access to different types and database links. Another nice feature of the database connection editors is the SQL editor which opens by default when you connect to a database.
However, the JDeveloper 11g technical preview does have some faults. Unfortunately, the faults will limit my exposure to the IDE until the bugs have been repaired. For instance, the database connections expansion tree is way too sensitive. It is hard to select a database package and/or body for editing. By default, when you select a database package or package body then it opens in a read-only mode. You must select a variable, function, or procedure definition in order to edit the package. This is too cumbersome for my liking. I hope that these changes can be made for the next release because I can definitely see the potential in this IDE.
Netbeans 6.0 M9 - Quick Review
The Milestone 9 release of Netbeans 6.0 has an abundance of new features to tout. I have only performed some basic editing and development tasks thus far. Therefore, I do not feel that I can give an informative review of this release. However, with my limited exposure this IDE milestone release is outstanding. I have not run into any bugs thus far. The editor reacts nicely and the new look and feel is great. Built-in profiler is a welcome feature as well.
The only disappointing feature of M9 that I have found so far is that it does not come fully equipped with Tomcat AS. You must download and install Tomcat separately if you wish to use that application server. M9 comes with Glassfish by default (which is nice), but I think many people are still using Tomcat and may not like the removal.
It has been a great month for the Java community! Check out the IDEs when you have a chance because both of them are worthy of a look or two.
http://www.oracle.com/technology/software/products/jdev/index.html
http://www.netbeans.org/community/releases/60/index.html
Tuesday, April 17, 2007
Essential Web Development Tool
I have been doing quite a bit of graphical design within my web development as of late. In previous web development projects, tools such as MS Paint and Open Office were good enough to complete the task. However, at times you may run across a task which cannot be completed with those basic image editing utilities.
I was about to break down and purchase the one and only Adobe Photoshop so that I could perform high-end image editing. Of all that I've heard, Photoshop is the ultimate image editing and graphic design software. That may be true, but have you ever heard of The GIMP, an open-source image manipulation program? If not, you may want to give it a spin.
I am able to complete every task imaginable with The GIMP, including image editing, text formatting, and even animation. Some of the tasks take a bit of work to complete, but there are a slew of online tutorials to help you along the way.
If you are in the need of an image manipulator, GIF creator, or just a cool imaging utility, give The GIMP a try.
I was about to break down and purchase the one and only Adobe Photoshop so that I could perform high-end image editing. Of all that I've heard, Photoshop is the ultimate image editing and graphic design software. That may be true, but have you ever heard of The GIMP, an open-source image manipulation program? If not, you may want to give it a spin.
I am able to complete every task imaginable with The GIMP, including image editing, text formatting, and even animation. Some of the tasks take a bit of work to complete, but there are a slew of online tutorials to help you along the way.
If you are in the need of an image manipulator, GIF creator, or just a cool imaging utility, give The GIMP a try.
Tuesday, April 10, 2007
Help Wanted: New Jython Monthly Editor
I have sent my last distribution of the Jython Monthly newsletter this morning. The choice to resign as editor of the newsletter comes about as a result of many changes which will impact my availability. I already do not have time to spend with the newsletter, and the April Newsletter shows it. I have not found the time to author articles for the newsletter as of late, and it has become increasingly difficult to find material for the distribution.
I'd like for someone to take over as editor of the newsletter as it is a great way to help increase the online Jython library and overall awareness of the language. If anyone is interested in taking over, please feel free to leave me a comment and let me know.
I'd like for someone to take over as editor of the newsletter as it is a great way to help increase the online Jython library and overall awareness of the language. If anyone is interested in taking over, please feel free to leave me a comment and let me know.
Tuesday, March 27, 2007
JPC
Check out the attached link...the JPC project offers computer virtualization in Java. Although I have only briefly reviewed the project, it looks to be very interesting and useful. Have a look...
Thursday, March 08, 2007
Just a Quick Note on FireBug
I have to blog about FireBug...the web development FireFox add-on. This tool is excellent, and it has helped me to find my javascripting bugs in a minimal amount of time. No more guessing which javascript line caused the bug, or using alert messages to find errors...Firebug allows one to traverse the javsscript while it is executing. This debugger is very similar to most IDE debuggers, and you can use it on any web page!
Love FireBug...if you have not tried it then I suggest downloading it now!
Love FireBug...if you have not tried it then I suggest downloading it now!
Jython Monthly Articles Needed
I am the editor and distributor of the Jython Monthly newsletter. Part of the monthly routine for ensuring an effective distribution is to obtain articles and blogs which are worth reading. I hate to throw together a newsletter full of garbage and waste the expensive time of the readers.
One of the reasons I started the Jython Monthly newsletter was to begin generating a more complete article library for Jython. I had hoped to obtain at least one or two articles per month for distribution with the newsletter. This worked well for a while, but we seem to have fallen into a slump as of late. Since the new year has begun, I've received very few articles for distribution with the newsletter. Therefore, I hope to see another spark in the community for generating useful Jython resources. We need more Jython articles!
If anyone has an article that they would like to contribute for this month or any coming month, please visit Jython Monthly Articles to get started. Anyone can contribute, so feel free to post any and all Jython related content.
Thanks for the help, and I look forward to reading your Jython Monthly article in the near future!
One of the reasons I started the Jython Monthly newsletter was to begin generating a more complete article library for Jython. I had hoped to obtain at least one or two articles per month for distribution with the newsletter. This worked well for a while, but we seem to have fallen into a slump as of late. Since the new year has begun, I've received very few articles for distribution with the newsletter. Therefore, I hope to see another spark in the community for generating useful Jython resources. We need more Jython articles!
If anyone has an article that they would like to contribute for this month or any coming month, please visit Jython Monthly Articles to get started. Anyone can contribute, so feel free to post any and all Jython related content.
Thanks for the help, and I look forward to reading your Jython Monthly article in the near future!
Friday, March 02, 2007
Old Buggy Details
I was reviewing an issue involving a record modification form within a PL/SQL web application yesterday. This modification form is basic...it displays the data which already exists within a database record and allows an end-user to modify that data within different text fields on the form.
The issue was that some of these text fields were not updating as expected. After some initial review, I saw that the records having this issue had been submitted without any data in the fields that were not updating. Furthermore, I checked the database and all varchar2 fields which were not updating as expected had NULL values within them. Ahh...the old NULL value comparison issue!!!
As it turns out, upon submitting a modified record, the PL/SQL application checks each field within the database to see if it's contents match the previously submitted data. If not, then the field and new content are added to the update statement so that the resulting modifications are submitted successfully. However, the comparison being used was not allowing for NULL values to be compared. The result was a false positive result which was prohibiting the data to be updated.
For example, the data is compared such as:
if cursor_rec.old_value != incoming_new_value then
update_text := update_text || ' my_field = ''' || upper(incoming_new_value)
|| ''';
end if;
The issue is that the above IF statement is never true if the varchar2 value contained within the incoming_new_value variable is NULL. You must always compare a varchar2 against a non-null value for obtaining a valid result in such cases. Therefore, the use of the Oracle nvl function comes into play.
The updated code which repairs the issue simply replaces a NULL value with a character so that comparisons will function as expected.
if cursor_rec.old_value != nvl(incoming_new_value, '*') then
update_text := update_text || ' my_field = ''' || upper(incoming_new_value)
|| ''';
end if;
An oldie but goodie to remember!!!
The issue was that some of these text fields were not updating as expected. After some initial review, I saw that the records having this issue had been submitted without any data in the fields that were not updating. Furthermore, I checked the database and all varchar2 fields which were not updating as expected had NULL values within them. Ahh...the old NULL value comparison issue!!!
As it turns out, upon submitting a modified record, the PL/SQL application checks each field within the database to see if it's contents match the previously submitted data. If not, then the field and new content are added to the update statement so that the resulting modifications are submitted successfully. However, the comparison being used was not allowing for NULL values to be compared. The result was a false positive result which was prohibiting the data to be updated.
For example, the data is compared such as:
if cursor_rec.old_value != incoming_new_value then
update_text := update_text || ' my_field = ''' || upper(incoming_new_value)
|| ''';
end if;
The issue is that the above IF statement is never true if the varchar2 value contained within the incoming_new_value variable is NULL. You must always compare a varchar2 against a non-null value for obtaining a valid result in such cases. Therefore, the use of the Oracle nvl function comes into play.
The updated code which repairs the issue simply replaces a NULL value with a character so that comparisons will function as expected.
if cursor_rec.old_value != nvl(incoming_new_value, '*') then
update_text := update_text || ' my_field = ''' || upper(incoming_new_value)
|| ''';
end if;
An oldie but goodie to remember!!!
Monday, February 26, 2007
Oracle ADF Faces
I've just read a great blog promoting the Oracle ADF Faces framework. I am an advocate of ADF Faces and I've used it in many of the applications which I have written. The open-sourced Gather! reunion application uses a version of ADF Faces which Oracle has open-sourced to Apache.
If you are a JSF developer and you have not yet worked with the framework, give it a chance and see how great it can be. I have found that the framework can save lots of time and it helps to create a professional layout.
If you are a JSF developer and you have not yet worked with the framework, give it a chance and see how great it can be. I have found that the framework can save lots of time and it helps to create a professional layout.
Wednesday, February 21, 2007
Another Fine JSF Component Library
I was performing my daily visual scrubbing of the java.net website this morning and I found a blurb about a new JSF component library called Woodstock. I briefly visited the project homepage and tested a few of the components. It looks as though this library could be a promising addition to the list of component libraries available for the JSF framework. While some of the basic components such as buttons and labels do not seem too different from stuff we've seen before, the Woodstock library has "Alert" and "Image and Masthead" components which may be very useful.
Check out the Woodstock JSF component library project page for more details, or go directly to the component preview to check out the features.
Check out the Woodstock JSF component library project page for more details, or go directly to the component preview to check out the features.
Tuesday, February 20, 2007
Best Jython/Python Podcasts
I am curious as to if anyone has any good links for podcasts relating to Jython or Python. I currently listen to Python 411 on a frequent basis, but I'd like to find out if there are any more very good podcasts for these subjects.
If you know of any other good Jython or Python podcasts, please leave me a comment!
Thanks
If you know of any other good Jython or Python podcasts, please leave me a comment!
Thanks
Thursday, February 15, 2007
Easy to Use Javascript Charting
I am currently working on a PL/SQL application which requires some simple charting. I have a defined set of trend data for which I must created a line chart...thus, displaying the trend for the data. I Googled javascript charting and found this javascript library. I cannot perform a complete review of the library because I have only used the line charting thus far, but I can tell you that the library is easy to use, flexible, and works great.
Using this library, it is possible to create one or many different charts on a web page. You can define static sets of data (does anyone do this anymore?) or use your database. I have found the line charting simple...especially with PL/SQL. The advantage of using PL/SQL to perform dynamic javascripting tasks is that your data is easily accessible.
I'll wrap up this blog with a quick example of line charting using PL/SQL and the JSGraph javascript library. If you have the need for a dynamic charting solution in your application, give JSGraph a look.
The following is an example of line charting in PL/SQL. In my particular case, I've defined a package which contains many different procedures. I recommmend using the PL/SQL Web Toolkit to define PL/SQL web applications. This is an exerpt from the procedure within my PL/SQL web package which defines my line chart:
(Please ignore the "-" within the tags...this blogger does not print tags well)
procedure GRAPH_TREND (in_trend_id number) is
cursor trend_cur is
select *
from my_trend_data
where trend_id = in_trend_id;
... more definitions ...
begin
... PL/SQL Code ...
-- Define Chart (Static data for this example)
htp.htmlopen;
htp.headopen;
htp.p('<-script language="JavaScript1.2" src="jsgraph.js"><-/script>
<-script language="JavaScript1.2">
var graph = new JSGraph();
graph.graphLeftPaddingOverride = 30;
graph.yAxis(4, 200);
graph.xAxis(4, 300);
graph.addBackground('#FFF8DC');
graph.addTrellis(40, 1, '#FF0000', 'blah1','tahoma,sans-serif',9);
graph.addTrellis(80, 1, '#FF0000', 'blah2','tahoma,sans-serif',9);
graph.addTrellis(120, 1, '#FF0000', 'blah3','tahoma,sans-serif',9);
graph.addTrellis(160, 1, '#FF0000', 'blah4','tahoma,sans-serif',9);
graph.addTrellis(200, 1, '#FF0000', 'blah5','tahoma,sans-serif',9);
graph.addLinePlot(0);
graph.addLinePlot(30,1,'maroon',1,'Foo 1','tahoma,sans-serif','maroon',9);
graph.addLinePlot(50,1,'maroon',1,'Foo 2','tahoma,sans-serif','black',9);
graph.addLinePlot(178,1,'maroon',1,'Foo 3','tahoma,sans-serif','maroon',9);
graph.addLinePlot(200,1,'maroon',1,'Foo 4','tahoma,sans-serif','black',9);
graph.addLinePlot(36,1,'maroon',1,'Foo 5','tahoma,sans-serif','maroon',9);
graph.addLinePlot(0,1,'maroon',1,'Foo 6','tahoma,sans-serif','black',9);
graph.addLinePlot(146,1,'maroon',1,'Foo 7','tahoma,sans-serif','maroon',9);
graph.addLinePlot(12,1,'maroon',1,'Foo 8','tahoma,sans-serif','black',9);
graph.addLinePlot(191,1,'maroon',1,'Foo 9','tahoma,sans-serif','maroon',9); <-/script>
');
htp.headclose;
htp.bodyopen;
htp.p('
<-div id="lineplotGraph1" style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; LEFT: 50px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px; POSITION: absolute; TOP: 50px">
<-script language="JavaScript">
graph.makeGraph();
<-/script>
<-/div>
');
htp.bodyclose;
htp.htmlclose;
...
end GRAPH_TREND;
Using this library, it is possible to create one or many different charts on a web page. You can define static sets of data (does anyone do this anymore?) or use your database. I have found the line charting simple...especially with PL/SQL. The advantage of using PL/SQL to perform dynamic javascripting tasks is that your data is easily accessible.
I'll wrap up this blog with a quick example of line charting using PL/SQL and the JSGraph javascript library. If you have the need for a dynamic charting solution in your application, give JSGraph a look.
The following is an example of line charting in PL/SQL. In my particular case, I've defined a package which contains many different procedures. I recommmend using the PL/SQL Web Toolkit to define PL/SQL web applications. This is an exerpt from the procedure within my PL/SQL web package which defines my line chart:
(Please ignore the "-" within the tags...this blogger does not print tags well)
procedure GRAPH_TREND (in_trend_id number) is
cursor trend_cur is
select *
from my_trend_data
where trend_id = in_trend_id;
... more definitions ...
begin
... PL/SQL Code ...
-- Define Chart (Static data for this example)
htp.htmlopen;
htp.headopen;
htp.p('<-script language="JavaScript1.2" src="jsgraph.js"><-/script>
<-script language="JavaScript1.2">
var graph = new JSGraph();
graph.graphLeftPaddingOverride = 30;
graph.yAxis(4, 200);
graph.xAxis(4, 300);
graph.addBackground('#FFF8DC');
graph.addTrellis(40, 1, '#FF0000', 'blah1','tahoma,sans-serif',9);
graph.addTrellis(80, 1, '#FF0000', 'blah2','tahoma,sans-serif',9);
graph.addTrellis(120, 1, '#FF0000', 'blah3','tahoma,sans-serif',9);
graph.addTrellis(160, 1, '#FF0000', 'blah4','tahoma,sans-serif',9);
graph.addTrellis(200, 1, '#FF0000', 'blah5','tahoma,sans-serif',9);
graph.addLinePlot(0);
graph.addLinePlot(30,1,'maroon',1,'Foo 1','tahoma,sans-serif','maroon',9);
graph.addLinePlot(50,1,'maroon',1,'Foo 2','tahoma,sans-serif','black',9);
graph.addLinePlot(178,1,'maroon',1,'Foo 3','tahoma,sans-serif','maroon',9);
graph.addLinePlot(200,1,'maroon',1,'Foo 4','tahoma,sans-serif','black',9);
graph.addLinePlot(36,1,'maroon',1,'Foo 5','tahoma,sans-serif','maroon',9);
graph.addLinePlot(0,1,'maroon',1,'Foo 6','tahoma,sans-serif','black',9);
graph.addLinePlot(146,1,'maroon',1,'Foo 7','tahoma,sans-serif','maroon',9);
graph.addLinePlot(12,1,'maroon',1,'Foo 8','tahoma,sans-serif','black',9);
graph.addLinePlot(191,1,'maroon',1,'Foo 9','tahoma,sans-serif','maroon',9); <-/script>
');
htp.headclose;
htp.bodyopen;
htp.p('
<-div id="lineplotGraph1" style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; LEFT: 50px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px; POSITION: absolute; TOP: 50px">
<-script language="JavaScript">
graph.makeGraph();
<-/script>
<-/div>
');
htp.bodyclose;
htp.htmlclose;
...
end GRAPH_TREND;
Friday, February 09, 2007
Jython 2.2 - Beta 1 - Part II
I have just finished installing Jython 2.2 beta1 without any issues. The installer is clean and easy to use. I am currently using Java SE 6 and this new Jython release had no problems installing.
I've only begun to test a few scripts out, but no issues thus far.
Thanks again to the Jython developers...it is great to see a new release!
I've only begun to test a few scripts out, but no issues thus far.
Thanks again to the Jython developers...it is great to see a new release!
Jython 2.2 Beta 1 Released
Wednesday, February 07, 2007
Snippets
Check out the new site from DZone which will be a repository for source code snippets. You can search the repository for existing code to use in your projects, or you can contribute some code which may be of use to others.
This is a great idea!
This is a great idea!
A Long Time Away
I have not posted for a while and I want to get back into the swing of things. My free time has been spent on side projects and I have not had much time to focus on new technologies as of late.
One technology I really want to focus more on is the Seam framework by JBoss. Seam takes the JSF framework and EJB 3 technology to a new level. It seems to ease development in this area while creating a more functional application development experience. I've only begun to look into the framework, but look for future blogs on this topic.
I'd also like to blog more on Jython. I have not had much time to spend with Jython as of late, but I'm still keeping up with the language. I will be distributing the February issue of Jython Monthly on 2/12, so keep an eye out for that.
Looking forward to a new year of great blogs...
One technology I really want to focus more on is the Seam framework by JBoss. Seam takes the JSF framework and EJB 3 technology to a new level. It seems to ease development in this area while creating a more functional application development experience. I've only begun to look into the framework, but look for future blogs on this topic.
I'd also like to blog more on Jython. I have not had much time to spend with Jython as of late, but I'm still keeping up with the language. I will be distributing the February issue of Jython Monthly on 2/12, so keep an eye out for that.
Looking forward to a new year of great blogs...