You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@struts.apache.org by "Todd G. Nist" <tn...@bellsouth.net> on 2002/02/05 22:00:03 UTC

MessageResources - Design question - loading resources from a DB by creating you own PropertyMessageResourcesFactory

Hello,

First, I would like to apologize for the size of this post.  I seem to be
missing one thing here and can't seem to put my finger on it.

We have a database which contains most of the translations for our
applications messages and database fields/column labels.  There is one table
which contains the messages, ApplicationResources, and another table called
field which contains general information about a field/column in the
database.  The field table is really only there to provide basic metadata
about columns like, the Column/Field label and some other basic information
which certain DB's do not provide.

There is one other table, Translations, which is made up of 3 columns
locale, stringID and transValue.

ApplicationResources		Translations			Field
--------------------		-------------------------	---------------------------
| key (pu) varchar |		| transValue    varchar |	| fieldID (pu) int        |
| message  varchar |---------<| stringID (pu) varchar |>----| fieldLabel
(pu) varchar |
--------------------		| locale (pu)   varchar |	| fieldName (pu) varchar  |
					-------------------------	---------------------------

I would like to load this information via my on
PropertyMessageResourcesFactory.  I have modified the web.xml to set the
parameter "factory" and set the <param-value> to my factory class,
DBMessageResourcesFactory.  The factory is called and my class,
BasePropertyMessageResources, is called and it appears as though all is
loaded in correctly based on the output being displayed below.  However,
whenever I use the <bean:message key="MLSBuyer.title"/> tag, it throws the
following exception:

[ServletException in:company/CompanyZoomBody.jsp] Missing message for key
MLSBuyer.title' javax.servlet.jsp.JspException: Missing message for key
MLSBuyer.title at
org.apache.struts.taglib.bean.MessageTag.doStartTag(MessageTag.java:298) at
org.apache.jsp.CompanyZoomBody$jsp._jspService(CompanyZoomBody$jsp.java:84)
at ........

Debugging messages displayed during execution:

===========================================
Config: ApplicationResources
===========================================
Completed BasePropertyMessageResources
Get MessageResources for key: org.apache.struts.action.MESSAGE
loading the following key: US.MLSBuyer.title with value MLSBuyer
loading the following key: US.button.cancel with value Cancel
loading the following key: US.button.save with value Save
loading the following key: US.button.update with value Update
loading the following key: FR.MLSBuyer.title with value MLSBuyer - French
loading the following key: FR.button.cancel with value FR Cancel
loading the following key: FR.button.save with value FR Save
loading the following key: FR.button.update with value FR Update
loading the following key: FR.MLSBuyer.title with value MLSBuyer - French
loading the following key: FR.button.cancel with value FR Cancel
loading the following key: FR.button.save with value FR Save
loading the following key: FR.button.update with value FR Update
loading the following key: US.CompanyName with value Company Name
loading the following key: FR.CompanyName with value French Company Name
loading the following key: FR.CompanyName with value French Company Name
===================================
/* Closing Translation Connection
===================================
===================================
/* Iterate over messages
===================================
US.button.cancel        Cancel
US.CompanyName  Company Name
US.button.save  Save
FR.button.update        FR Update
US.button.update        Update
FR.CompanyName  French Company Name
US.MLSBuyer.title       MLSBuyer
FR.button.cancel        FR Cancel
FR.MLSBuyer.title       MLSBuyer - French
FR.button.save  FR Save

I have extend the ActionServlet class and added the following
"initApplication()" method, this much seems to work fine.

    public void initApplication() throws ServletException {
        super.initApplication();

        String dataSource =
getServletConfig().getInitParameter("datasource");

        if (dataSource != null && !dataSource.equals("")) {
            getServletContext().setAttribute("DATASOURCE", dataSource);
        }

        System.out.println("Get MessageResources for key: " +
Action.MESSAGES_KEY);
        MessageResources mr =
(MessageResources)getServletContext().getAttribute(Action.MESSAGES_KEY);

        if (mr == null) {
            System.out.println("Message Resource is invalid....");
            return;
        }
	  // load resources from the dataSource
        ((BasePropertyMessageResources)mr).dbLoad(dataSource);

    }

The MessageResources classs, BasePropertyMessageResources, is as follows and
seems to build messages just fine:

public class BasePropertyMessageResources extends PropertyMessageResources {

    private static final Category log =
Category.getInstance("BaseProperyMessageResources");

    private static final String[] SELECT_TRANSLATIONS = { "select * from
ApplicationResources left join Translations " +
                                                          "on
ApplicationResources.message = Translations.stringID " +
                                                          "where
Translations.Locale = ?",
                                                          "select * from
Field left join Translations " +
                                                          "on
Field.FieldLabel = Translations.stringID " +
                                                          "where
Translations.Locale = ?" };

    public BasePropertyMessageResources(MessageResourcesFactory factory,
String config){
        super(factory, config);
    }

    public BasePropertyMessageResources(MessageResourcesFactory factory,
String config,
                                      boolean returnNull) {
        super(factory, config, returnNull);
        System.out.println("Completed BasePropertyMessageResources");
    }


    /**
     * Load the messages HashMap with information maintined in datasource
     *
     * @param dataSource - name of datasource to connect to via poolman
     */
    public void dbLoad(String dataSource) {

        Connection connection = null;
        // hold locales supported on the system
        Locale[] lArray = Locale.getAvailableLocales();
        // variable to hold the resultset of the query
        ResultSet result = null;
        // variable to hold prepared statement for translations
        PreparedStatement pstmt = null;

        try {
            connection = ConnectionPool.getConnection(dataSource);
            for (int x = 0; x < SELECT_TRANSLATIONS.length; x++) {
                pstmt = connection.prepareStatement(SELECT_TRANSLATIONS[x],
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
                for ( int i = 0 ; i < lArray.length ; i ++ ) {
                    pstmt.setString(1, lArray[i].getCountry());
                    result = pstmt.executeQuery();
                    synchronized (messages) {
                        while (result.next()) {
    				    String key = x == 0 ?
result.getString("key"):result.getString("FieldName");
                            System.out.println("loading the following key: "
+ messageKey(lArray[i].getCountry(), key) +
                                      " with value " +
result.getString("TransValue"));
                            messages.put(messageKey(lArray[i].getCountry(),
key), result.getString("TransValue"));
                                                }
                    }
                    // close result set to free resources
                    result.close();
                } // ---- for i < lArray.length
            } // ---- for x < SELECT_TRANSLATIONS


        } catch(SQLException sqle) {
            log.error("Exception reading translation db.", sqle);
        }
        finally {
            try {
                System.out.println("===================================");
                System.out.println("/* Closing Translation Connection");
                System.out.println("===================================");
                // close statement to free resources
                pstmt.close();
                if (connection != null)
                    connection.close();
            } catch (SQLException sqle) {
                log.error("Exception disconnecting form translation db.",
sqle);
            }
        }
        /**
         * Debug
         *
         * Loop through messages to ensure the values were created
         *
         */
        Set set = messages.keySet();
        Iterator it = set.iterator();
	  System.out.println("===================================");
	  System.out.println("/* Iterate over messages");
        while (it.hasNext()) {
            String s = (String)it.next();
            System.out.println(s + "\t" + messages.get(s));
        }
	  System.out.println("===================================");
        return;
    }

}

Finally, the factory, DBMessageResourcesFactory, looks like the following:

public class DBMessageResourcesFactory extends MessageResourcesFactory {


    // --------------------------------------------------------- Public
Methods


    /**
     * Create and return a newly instansiated <code>MessageResources</code>.
     * This method must be implemented by concrete subclasses.
     *
     * @param config Configuration parameter(s) for the requested bundle
     */
    public MessageResources createResources(String config) {

        System.out.println("===========================================");
        System.out.println("Config: " + config);
        System.out.println("===========================================");

        return new BasePropertyMessageResources(this, config,
this.returnNull);

    }

}



So what am I missing here?  Any ideas or suggestions are appreciated.

Thanks in advance.

Regards,
Todd G. Nist
Email:   tnist@fbos.com