Matt RaibleMatt Raible is a writer with a passion for software. Connect with him on LinkedIn.

The Angular Mini-Book The Angular Mini-Book is a guide to getting started with Angular. You'll learn how to develop a bare-bones application, test it, and deploy it. Then you'll move on to adding Bootstrap, Angular Material, continuous integration, and authentication.

Spring Boot is a popular framework for building REST APIs. You'll learn how to integrate Angular with Spring Boot and use security best practices like HTTPS and a content security policy.

For book updates, follow @angular_book on Twitter.

The JHipster Mini-Book The JHipster Mini-Book is a guide to getting started with hip technologies today: Angular, Bootstrap, and Spring Boot. All of these frameworks are wrapped up in an easy-to-use project called JHipster.

This book shows you how to build an app with JHipster, and guides you through the plethora of tools, techniques and options you can use. Furthermore, it explains the UI and API building blocks so you understand the underpinnings of your great application.

For book updates, follow @jhipster-book on Twitter.

10+ YEARS


Over 10 years ago, I wrote my first blog post. Since then, I've authored books, had kids, traveled the world, found Trish and blogged about it all.
You searched this site for "param". 72 entries found.

You can also try this same search on Google.

Building high-content web applications

I've recently been tasked with rebuilding a JSP-based site using a Struts architecture. One of the issues (that I see) in the current architecture is that there are a number of JSPs with the text for the pages hard-coded in them. After re-writing this app, we plan on deploying it to 25+ customers - and we certainly don't want to have 25 different JSPs (with text) for each customer. I've proposed a database, but that might be a little resource intensive - so I'm wondering how folks have done this in the past (I'm sure it's been done before)?

Options I see are:

  • A Database table with the following columns (page_id, title, content, section_id).
  • Text files that are imported using <c:import url=""/>

What options have you used (feel free to add more) - if you've used the database approach - how do you define the page table? Maybe we should use the Roller way and use Velocity and OSCache.

Posted in Java at Aug 19 2003, 06:30:28 PM MDT 18 Comments

Changing Struts' bean:message to JSTL's fmt:message

I converted AppFuse to use JSTL's <fmt:message> tag instead of Struts' <bean:message> tags this morning. It was pretty easy. Here's the steps I took:

1. First, I added the following to metadata/web/seb-settings.xml:

<!-- Define the basename for a resource bundle for I18N -->
<context-param>
    <param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
    <param-value>ApplicationResources</param-value>
</context-param>

2. Then I added the format tag to web/common/taglibs.jsp:

<%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %>

3. Finally, I did find/replace with <bean:message/<fmt:message.

4. I also had to change my title and header keys in web/WEB-INF/tiles-config.xml to remove the . from the bean names. In other words, I converted title.key and heading.key to titleKey and headingKey and also made the appropriate changes in web/layouts/baseLayout.jsp.

Easy as Pie!

Posted in Java at Jul 10 2003, 07:59:29 AM MDT 35 Comments

Hibernate Upgrade (1.2.4 to 2.0 rc1) Redux

My last upgrade from Hibernate 1.2.x to 2.0.x was a little rocky, so I'm going to document it again today - this time with a Hibernate 2.0-enabled version of XDoclet, and code samples from last time. Today I'm upgrading from 1.2.4 to 2.0 rc1.

1. First, I downloaded Hibernate 2.0 rc1. BTW, I also updated to the latest version of XDoclet from CVS.

2. Next, I copied it to my project's lib directory, deleted bin, doc, and src directories. The only files I need are hibernate2.jar and (in the lib folder) c3p0.jar, cglib.jar, dom4j.jar, jcs.jar, jdom.jar and odmg.jar. One thing to note is with Hibernate 1.2.x, I didn't need dom4j.jar, jdom.jar or cglib.jar in my deployed WEB-INF/lib folder. However, with the new version, I did need to include them.

3. Then I updated lib/lib.properties and began changing my code with gool ol' Homesite.

4. Hey, step 4 is the same as last time! Edit build.xml file to pick up the new DTD. I changed <hibernate/> to be <hibernate validatexml="true" version="2.0"/>.

5. Using HomeSite, I did s/cirrus.hibernate/net.sf.hibernate/g for all my .java and .xml files. Don't forget to change your log4.properties and hibernate.properties files.

6. In hibernate.cfg.xml I changed cirrus.hibernate.sql.OracleDialect to net.sf.hibernate.dialect.OracleDialect. I also updated the DTD to 2.0 and moved all properties inside the <session-factory> element. Here's a sample hibernate.cfg.xml file from struts-resume.

7. In my ServiceLocator.java class, I changed the following from (this is so JUnit Tests can run w/o JNDI):

Datastore datastore = Hibernate.createDatastore();
datastore.storeClass(package.MyClass.class); // lots of these
sf = datastore.buildSessionFactory();

To:

sf = new Configuration().addClass(MyClass.class) // lots of these
                        .buildSessionFactory();

8. Time to bring Eclipse to the table. I refreshed the project and added the new hibernate2.jar to the "Java Build Path."

9. In my StartupListener.java (which initializes Hibernate for Tomcat), I changed the following code:

// Configure Hibernate.
try {
    Hibernate.configure();

    if (log.isDebugEnabled()) {
        log.debug("Hibernate configuration completed.");
    }
} catch (HibernateException h) {
    log.fatal("Error configuring Hibernate!", h);
}

To:

try {
    SessionFactory sf =
        new Configuration().configure().buildSessionFactory();

    if (log.isDebugEnabled()) {
        log.debug("Hibernate configuration completed.");
    }
} catch (HibernateException h) {
    log.fatal("Error configuring Hibernate!", h);
}

10. Changed all instances of readonly="true" to inverse="false" inverse="true" for XDoclet tags. Also changed role to name.

11. Removed length attribute from any <key-property ... /> elements in my .hbm.xml files. These were rudely put there by the ReverseGenerator. Not all my mapping files are generated by XDoclet, if I have one with a composite-id, I just create the mapping file manually. I also had the change the DTD manually in these files.

12. In my build.xml, I changed the SchemaExport class from net.sf.hibernate.tools to net.sf.hibernate.tool.hbm2ddl.

13. OK, here goes, my first attempt at compiling (honestly!). Darn - I forgot to save StartupListener.java - trying again (this time with "ant clean" first). Sweeeet - it worked!

14. Hmmm, some log messages I wasn't expecting. I forgot to change my log4j.properties file from cirrus.hibernate to net.sf.hibernate. I'll add this above (step 5) to make this how to more accurate.

15. Running persistence tests - since I keep my Oracle driver (ojdbc14.jar) in ${hibernate.dir}/lib, I had to move it to the new directory. Now this is a strange error:

[junit] 2003-04-29 13:14:50,968 INFO [main] Configuration.addClass(264) | Mapping resource: com/
.../persistence/ChangeRequest.hbm.xml
[junit] 2003-04-29 13:14:51,234 ERROR [main] XMLHelper$ErrorLogger.error(37) | Error parsing XML
: XML InputStream(19)
[junit] org.xml.sax.SAXParseException: Attribute "name" is required and must be specified for el
ement type "param".

My guess is that it's being caused by:

<generator class="sequence">
    <param>cr_master_sq</param>
</generator>

After reading the Hibernate2 Porting Guidelines, looks like I need to add a name attribute. Didn't the exception tell me that! ;0)

I'll update this post when I figure out the answer to my question on Hibernate's forums...

Update: I had to 1) upgrade my XDoclet JARs, and 2) replace the following XDoclet tags:

* @hibernate.id column="cr_id" unsaved-value="null"
*  generator-class="sequence" generator-parameter-1="cr_master_sq"

with:

* @hibernate.id column="cr_id" unsaved-value="null" generator-class="sequence" 
* @hibernate.generator-param name="sequence" value="cr_master_sq" 

Now I'm experiencing this issue.

Update 2: I discovered (from Gavin) that readonly="true" is the same as inverse="true". I've updated step 10 above, and now my upgrade is complete!

Posted in Java at Apr 29 2003, 02:52:07 PM MDT Add a Comment

Making your tables more accessible?

A question was asked on the display tag user list recently. Basically, the user wanted to add onmouseover and onmouseout events to the <tr>'s in a display-tag rendered table. Today, I decided to whip up a quick example of how to do this in a DOM-compliant browser. Just add an "id" attribute to your table, or use document.getElementsByTagName("table") (selecting the appropriate table in the array), and then put the following JavaScript block below your table. Of course, you must define a "tr.over" class in your CSS.

<script type="text/javascript">
    var table = document.getElementById("testTable");
    var rows = table.getElementsByTagName("tr");
    for (i=0; i < rows.length; i++) {
        rows[i].onmouseover = function() { this.className='over' };
        rows[i].onmouseout = function() { this.className='' };
    }
</script>

Now for an example:

       
       
       
       
       
       

Later: You can take this one step further and add an "onclick" event so that the user can edit the record the row is referring to. Let's pretend you have a link in the first <td> of the table. Inside this link is the recordId for that row. Adding an onclick to the row makes it easy to route the user to the details page for the record.

rows[i].onclick = function() {
    var cell = this.getElementsByTagName("td")[0];
    var link = cell.firstChild;
    var id = link.firstChild.nodeValue;
    location.href='URL to details page?recordId='+id;
    this.style.cursor="wait";
}

Posted in The Web at Apr 22 2003, 04:55:25 PM MDT 25 Comments

Use Maven? Experience says no...

I've been wanting to upgrade struts-resume to use Maven, but after reading Patrick's post, I might just change my mind.

And after 2 years of using Ant, Maven (which uses Jelly and Werkz as the underlying engines) behaves differently enough from Ant to utterly frustrate me. So I'm back heading back to the drawing board for new ideas.

Of course, my hope is to integrate Maven without losing Ant and let them both live beside each other intimately. Someday it will be done...

Posted in Java at Feb 23 2003, 04:30:52 PM MST 1 Comment

My First Attempt at ConvertUtils

My first attempt at using ConvertUtils is turning out to be a painful one - most likely due to my own ignorance. Let's see if you can help me out. I have a Hibernate Bag, which is really a java.util.List on my User object. When I run the User object through XDoclet, I create a UserForm (extends ValidatorForm). The form has an ArrayList on for any instances of List or Set on the object (set through a custom struts_form.xdt template). So I created a ListConverter to convert a List object to an ArrayList. Sounds pretty simple right?! Here's my ListConverter.java:

public class ListConverter implements Converter {
    //~ Instance fields ========================================================

    protected Log log = LogFactory.getLog(ListConverter.class);

    //~ Methods ================================================================

    /**
     * Convert a List to an ArrayList
     *
     * @param type the class type to output
     * @param value the object to convert
     */
    public Object convert(Class type, Object value) {
        if (log.isDebugEnabled()) {
            log.debug("entering 'convert' method");
        }

        // for a null value, return null
        if (value == null) {
            return null;
        } else if (value instanceof Set && (type == Set.class)) {
            return new ArrayList((Set) value);
        } else if (value instanceof List && (type == List.class)) {
            return new ArrayList((List) value);
        } else {
            throw new ConversionException("Could not convert " + value
                                          + " to ArrayList!");
        }
    }
}

When I run BeanUtils.copyProperties(userForm, user), I get:

Could not convert cirrus.hibernate.collections.Bag@e2892b to ArrayList!

On another class, where I am trying to convert a List of Longs, I get:

Could not convert [-1, 1, 30129] to ArrayList!

I'm registering my custom converter in a static block of my BaseManager class. My *Manager classes do all the conversions, so this seems logical:

static {
    ConvertUtils.register(new StringConverter(), String.class);
    ConvertUtils.register(new LongConverter(), Long.class);
    ConvertUtils.register(new ListConverter(), ArrayList.class);
	
    if (log.isDebugEnabled()) {
        log.debug("Converters registered...");
    }
}

Since I'm in a major time crunch, I'll try simply making my getter/setters on my UserForm to be List. I'd like to use ConvertUtils though, so hopefully someone has a solution.

This brings me to a RANT and I think it's my first official one. My last three projects have always started small, and the goal has always been a prototype of functionality. A prototype that turns into a production system. All fricken three of them. All were supposed to take about 3 months to develop initially. The last two projects took at least 6 months. This one has a one month deadline, but the scope is a lot smaller than the previous two. But still, it's always the same scenario - the clients want a prototype, but turn it into a production system. Since it's a prototype, I tend to write "workarounds" for design patterns (see above) that I can't figure out. Is this good? It probably doesn't hurt since no one will ever look at my code - right?! When's the last time you looked at a co-workers code? (The more == the better). And the truth is, as long as it works - it's probably good enough. However, I as a developer, get heartburn when I think about maintaining the system that I created under the impression that it was a prototype. Maybe one of these days I'll figure out all the best practices to creating a robust web application, and then I'll know everything - so I won't have to write workarounds for my lack of knowledge. If you see some pigs flying, you can think to yourself - "Wow, Raible must've figured it all out" ;-)

Posted in Java at Jan 11 2003, 04:04:43 PM MST 1 Comment

PlugIns and Struts Nightly Build

I had a nice frustrating evening tonight trying to get the nightly build of Struts to work with Tiles, Modules and the Struts Menu. Actually, it wasn't a Struts problem so much as a Struts Menu problem. I was getting a java.lang.AbstractMethodError error when hitting the first action class, and couldn't figure out why. I started by bitching to the struts-dev list, and then filed a bug. Eddie Bush was kind enough to suggest that there was something wrong with my PlugIns. I thought - how could there be - I'm using Tiles and Validator? So I looked at my struts-plugins.xml file and there was the culprit - struts-menu. It turns out that I needed to add the following variable and method to MenuPlugIn.java:

/** The plugin config object provided by the ActionServlet initializing
 *  this plugin.
 */
protected PlugInConfig currentPlugInConfigObject;

/**
 * Method used by the ActionServlet initializing this plugin.
 * Set the plugin config object read from module config.
 * @param currentPlugInConfigObject
 */
public void setCurrentPlugInConfigObject(PlugInConfig currentPlugInConfigObject) {
    this.currentPlugInConfigObject = currentPlugInConfigObject;
}

This post was written in hopes of alleviating someone else's troubles with this same problem.

Posted in Java at Dec 28 2002, 02:00:47 AM MST Add a Comment

Ant won't delete a file - any ideas?

I've been experiencing this problem for the last couple of days. Basically, when I run "ant clean" on my project, I get the following error:

file:d:/source/appfuse/build.xml:746: 
  Unable to delete file D:\source\appfuse\dist\appfuse-common.jar

I can delete the "dist" directory in Explorer, and also using "rm -r dist" in Cygwin. Any ideas why Ant is choking on this all of a sudden?

Posted in Java at Dec 26 2002, 05:05:32 PM MST 18 Comments

Using one JSP for form-based authentication

I'm writing about how to use the same login/error page with form-based authentication. Does anyone know which servlet containers this fails on? I guess it wouldn't hurt to know which ones it works on too. You can use this security.war (1.7MB) file to test. Since it's testing the failure page, you don't need to setup a user - but if you want, the role is tomcat. I know this works on Tomcat, so no need to test it.

Posted in General at Dec 05 2002, 10:27:20 AM MST 6 Comments

Using XDoclet on Large Projects

Kurt emerges from his sabbatical (12 days is a long time in blogsphere) and mentions a little tidbit I'd like to comment on:

Last week I attending a TC JUG meeting where the topic was Struts 1.1: The Good, the Bad and the Ugly.
...
Interestingly the speaker didn't like XDoclet because he felt that on large development teams the config files should be managed outside of the source code during the design phase. Since I have never worked on a large team (not that I won't want to) I don't know if his concern is valid. Interesting comment though.

(I added the bold.) First of all, I have only recently (last 6 months) found XDoclet, and all the projects I've been on (in my entire life) have always had less than 5 coders. I've been on teams as large as 20, but the module I was working on never involved everyone. In my experience, the design phase never really consists of writing very much code or configuration, but rather a bunch of UML diagrams and static HTML prototypes.

I have found (in my brief work on struts-xdoclet) that I need to change values in my web.xml to test different settings (i.e. a servlet's init-param). However, since I'm coding some of these values in my classes, in order to change and test, I have to re-compile and deploy. Of course, I could just change the values in web.xml after I've deployed, but that's just a workaround.

A better solution, which I hope to implement, is to put certain values in my classes as tokens (i.e. @encrypt-password@) and then I can use Ant's replace task to specify this value from the command line. That way, I can set the default in my build.xml file and change it by either 1) specifying the property in build.properties, or 2) specifying it from the command line (i.e. ant -Dencrypt-password=true).

I'd be very interested in hearing anyone's war stories on this topic (managing config files in a large team).

Posted in Java at Nov 27 2002, 12:31:26 PM MST 2 Comments