Package org.apache.click.extras.hibernate

Source Code of org.apache.click.extras.hibernate.HibernateForm

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.click.extras.hibernate;

import java.io.Serializable;

import org.apache.click.control.Checkbox;
import org.apache.click.control.Field;
import org.apache.click.control.Form;
import org.apache.click.control.HiddenField;
import org.apache.click.util.ClickUtils;

import org.apache.click.util.HtmlStringBuffer;
import org.apache.commons.lang.StringUtils;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.type.Type;

/**
* Provides Hibernate data aware Form control:   <form method='POST'>.
*
* <table class='htmlHeader' cellspacing='10'>
* <tr>
* <td>
*
* <table class='fields'>
* <tr>
* <td align='left'><b><label>First Name:</label></b></td>
* <td align='left'><input type='text' name='name' value='' size='20' /></td>
* </tr>
* <tr>
* <td align='left'><label>Middle Names:</label></td>
* <td align='left'><input type='text' name='name' value='' size='20' /></td>
* </tr>
* <tr>
* <td align='left'><b><label>Family Name:</label></b></td>
* <td align='left'><input type='text' name='name' value='' size='20' /></td>
* </tr>
* </table>
* <table class="buttons" align='right'>
* <tr><td>
* <input type='submit' name='ok' value='   OK   '/>&nbsp;<input type='submit' name='cancel' value='Cancel'/>
* </td></tr>
* </table>
*
* </td>
* </tr>
* </table>
*
* <a href="http://www.hibernate.org/">Hibernate</a> is an Object Relational
* Mapping (ORM) framework. The HibernateForm supports creating (inserting) and
* saving (updating) POJO instances. This form will automatically apply the
* given objects property required validation constraints to the form fields.
* <p/>
* The HibernateForm uses the thread local <tt>Session</tt> obtained via
* <tt>SessionContext.getSession()</tt> for all object for persistence
* operations. To use an alternative Session source override set the forms
* getSession() method.
* <p/>
* The example below provides a <tt>User</tt> data object creation
* and editing page. To edit an existing user object, the object is passed
* to the page as a request parameter. Otherwise a new user object will
* be created when {@link #saveChanges()} is called.
*
* <pre class="codeJava">
* <span class="kw">public class</span> UserEdit <span class="kw">extends</span> Page {
*
*   <span class="kw">private</span> HibernateForm form = <span class="kw">new</span> HibernateForm(<span class="st">"form"</span>, User.<span class="kw">class</span>);
*
*    <span class="kw">public</span> UserEdit() {
*        form.add(<span class="kw">new</span> TextField(<span class="st">"firstName"</span>));
*        form.add(<span class="kw">new</span> TextField(<span class="st">"middleNames"</span>));
*        form.add(<span class="kw">new</span> TextField(<span class="st">"FamilyName"</span>));
*
*        form.add(<span class="kw">new</span> Submit(<span class="st">"ok"</span>, <span class="st">"   OK   "</span>, <span class="kw">this</span>, <span class="st">"onOkClicked"</span>));
*        form.add(<span class="kw">new</span> Submit(<span class="st">"cancel"</span>, <span class="kw">this</span>, <span class="st">"onCancelClicked"</span>));
*
*        form.setButtonAlign(<span class="st">"right"</span>);
*        form.setLabelRequiredPrefix(<span class="st">"&lt;b&gt;"</span>);
*        form.setLabelRequiredSuffix(<span class="st">"&lt;/b&gt;"</span>);
*        addControl(form);
*    }
*
*    <span class="kw">public void</span> setUser(User user) {
*        form.setValueObject(user);
*    }
*
*    <span class="kw">public boolean</span> onOkClicked() {
*        <span class="kw">if</span> (form.isValid()) {
*           <span class="kw">if</span> (form.saveChanges()) {
*               setRedirect(<span class="st">"user-list.htm"</span>);
*           }
*        }
*        <span class="kw">return true</span>;
*    }
*
*    <span class="kw">public boolean</span> onCancelClicked() {
*        setRedirect(<span class="st">"user-list.htm"</span>);
*        <span class="kw">return false</span>;
*    }
* } </pre>
*
* @see SessionContext
* @see SessionFilter
*/
public class HibernateForm extends Form {

    private static final long serialVersionUID = -7134198516606088333L;

    /** The form value object classname parameter name. */
    protected static final String FO_CLASS = "FO_CLASS";

    /** The form value object id parameter name. */
    protected static final String FO_ID = "FO_ID";

    // ----------------------------------------------------- Instance Variables

    /** The value object class name hidden field. */
    protected HiddenField classField;

    /** The value object identifier hidden field. */
    protected HiddenField oidField;

    /** The Hibernate session. */
    protected Session session;

    /** The Hibernate session factory. */
    protected SessionFactory sessionFactory;

    /**
     * The flag specifying that object validation meta data has been applied to
     * the form fields.
     */
    protected boolean metaDataApplied = false;

    // ----------------------------------------------------------- Constructors

    /**
     * Create a new HibernateForm with the given form name and value object
     * class.
     *
     * @param name the form name
     * @param valueClass the value object class
     */
    public HibernateForm(String name, Class valueClass) {
        super(name);

        if (valueClass == null) {
            throw new IllegalArgumentException("Null valueClass parameter");
        }

        classField = new HiddenField(FO_CLASS, String.class);
        classField.setValue(valueClass.getName());
        add(classField);

        String classname = getClassname(valueClass);

        ClassMetadata classMetadata =
            getSessionFactory().getClassMetadata(classname);

        Type identifierType = classMetadata.getIdentifierType();
        oidField = new HiddenField(FO_ID, identifierType.getReturnedClass());
        add(oidField);
    }


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

    /**
     * Return the form Hibernate <tt>Session</tt>. If form session is not
     * defined this method will obtain a session from the
     * {@link SessionContext}.
     * <p/>
     * Applications using alternative Hibernate <tt>Session</tt> sources should
     * set the form's session using the {@link #setSession(Session)} method.
     *
     * @return the form Hibernate session
     */
    public Session getSession() {
        if (session == null) {
            session = SessionContext.getSession();
        }
        return session;
    }

    /**
     * Set the user's Hibernate <tt>Session</tt>.
     *
     * @param session the user's Hibernate session
     */
    public void setSession(Session session) {
        this.session = session;
    }

    /**
     * Return the application Hibernate <tt>SessionFactory</tt>.
     * If session factory is not defined this method will obtain the session
     * factory from the {@link SessionContext}.
     * <p/>
     * Applications using an alternative Hibernate <tt>SessionFactory</tt>
     * sources should set the form's session factory using the
     * {@link #setSessionFactory(SessionFactory)} method.
     *
     * @return the user's Hibernate session
     */
    public SessionFactory getSessionFactory() {
        if (sessionFactory == null) {
            sessionFactory = SessionContext.getSessionFactory();
        }
        return sessionFactory;
    }

    /**
     * Set the form Hibernate <tt>SessionFactory</tt>.
     *
     * @param sessionFactory the Hibernate SessionFactory
     */
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    /**
     * Return a Hibernate value object from the form with the form field values
     * copied into the object's properties.
     *
     * @return the Hibernate object from the form with the form field values
     * applied to the object properties.
     */
    public Object getValueObject() {
        if (StringUtils.isNotBlank(classField.getValue())) {
            try {
                Class valueClass = ClickUtils.classForName(classField.getValue());

                Serializable oid = (Serializable) oidField.getValueObject();

                Object valueObject = null;
                if (oid != null) {
                    valueObject = getSession().load(valueClass, oid);
                } else {
                    valueObject = valueClass.newInstance();
                }

                copyTo(valueObject);

                return valueObject;

            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return null;
    }

    /**
     * Set the given Hibernate value object in the form, copying the object's
     * properties into the form field values.
     *
     * @param valueObject the Hibernate value object to set
     */
    public void setValueObject(Object valueObject) {
        if (valueObject != null) {

            String classname = getClassname(valueObject.getClass());

            ClassMetadata classMetadata =
                getSessionFactory().getClassMetadata(classname);

            Object identifier =
                classMetadata.getIdentifier(valueObject, EntityMode.POJO);
            oidField.setValueObject(identifier);

            copyFrom(valueObject);
        }
    }

    /**
     * Save or update the object to the database and return true.
     * If a <tt>HibernateException</tt> occurs the <tt>Transaction</tt> will be
     * rolled back the exception will be raised.
     * <p/>
     * If no object is added to the form using <tt>setValueObject()</tt>
     * then this method will: <ul>
     * <li>create a new instance of the Class</li>
     * <li>copy the form's field values to the objects properties</li>
     * <li>save the new object to the database</li>
     * </ul>
     * <p/>
     * If an existing persistent object is added to the form using
     * <tt>setValueObject()</tt> then this method will: <ul>
     * <li>load the persistent object record from the database</li>
     * <li>copy the form's field values to the objects properties</li>
     * <li>update the object in the database</li>
     * </ul>
     *
     * @return true if the object was saved or false otherwise
     * @throws HibernateException if a persistence error occured
     */
    public boolean saveChanges() throws HibernateException {
        Object valueObject = getValueObject();

        Transaction transaction = null;
        try {
            Session session = getSession();

            transaction = session.beginTransaction();

            session.saveOrUpdate(valueObject);

            transaction.commit();

            return true;

        } catch (HibernateException he) {
            if (transaction != null) {
                try {
                   transaction.rollback();
                } catch (HibernateException re) {
                    // ignore
                }
            }
            throw he;
        }
    }

    /**
     * This method applies the object meta data to the form fields and then
     * invokes the <tt>super.onProcess()</tt> method.
     *
     * @see Form#onProcess()
     *
     * @return true to continue Page event processing or false otherwise
     */
    public boolean onProcess() {
        applyMetaData();
        return super.onProcess();
    }

    /**
     * Render the HTML representation of the HibernateForm.
     * <p/>
     * This method applies the object meta data to the form fields and then
     * invokes the <tt>super.toString()</tt> method.
     *
     * @see #toString()
     *
     * @param buffer the specified buffer to render the control's output to
     */
    public void render(HtmlStringBuffer buffer) {
        applyMetaData();
        super.render(buffer);
    }

    // ------------------------------------------------------ Protected Methods

    /**
     * Applies the <tt>ClassMetadata</tt> validation database meta data to the
     * form fields.
     * <p/>
     * The field validation attributes include:
     * <ul>
     * <li>required - is a mandatory field and cannot be null</li>
     * </ul>
     */
    protected void applyMetaData() {
        if (metaDataApplied) {
            return;
        }

        try {
            Class valueClass = ClickUtils.classForName(classField.getValue());

            String classname = getClassname(valueClass);

            ClassMetadata metadata = getSessionFactory().getClassMetadata(classname);

            String[] propertyNames = metadata.getPropertyNames();

            boolean[] propertyNullability = metadata.getPropertyNullability();

            for (int i = 0; i < propertyNames.length; i++) {
                Field field = getField(propertyNames[i]);
                if (field != null) {
                    boolean isMandatory = !propertyNullability[i];
                    if (!field.isRequired() && isMandatory) {
                        if (!(field instanceof Checkbox)) {
                            field.setRequired(true);
                        }
                    }
                }
            }

        } catch (ClassNotFoundException cnfe) {
            throw new RuntimeException(cnfe);
        }

        metaDataApplied = true;
    }

    /**
     * Return the original classname for the given class removing any CGLib
     * proxy information.
     *
     * @param aClass the class to obtain the original name from
     * @return the original classname for the given class
     */
    protected String getClassname(Class aClass) {

        String classname = aClass.getName();
        if (classname.indexOf("$$") != -1) {
            classname = classname.substring(0, classname.indexOf("$"));
        }

        return classname;
    }

}
TOP

Related Classes of org.apache.click.extras.hibernate.HibernateForm

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.