Package org.geoserver.rest.format

Source Code of org.geoserver.rest.format.ReflectiveHTMLFormat$ObjectToMapWrapper

/* Copyright (c) 2001 - 2007 TOPP - www.openplans.org.  All rights reserved.
* This code is licensed under the GPL 2.0 license, availible at the root
* application directory.
*/
package org.geoserver.rest.format;

import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.geoserver.ows.util.ClassProperties;
import org.geoserver.ows.util.OwsUtils;
import org.geoserver.rest.PageInfo;
import org.geotools.util.logging.Logging;
import org.restlet.data.MediaType;
import org.restlet.data.Request;
import org.restlet.data.Response;
import org.restlet.ext.freemarker.TemplateRepresentation;
import org.restlet.resource.Representation;
import org.restlet.resource.Resource;

import freemarker.core.ParseException;
import freemarker.ext.beans.BeansWrapper;
import freemarker.ext.beans.CollectionModel;
import freemarker.ext.beans.MapModel;
import freemarker.template.Configuration;
import freemarker.template.ObjectWrapper;
import freemarker.template.SimpleHash;
import freemarker.template.Template;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;

/**
* Data format for serializing objects as HTML.
* <p>
* <h2>Template Lookup</h2>
* When serializing an object the following this class looks up a template using the
* following methods:
* <ol>
*   <li>The result of {@link #getTemplateName(Object)} if not null.
*   <li>The resource uri being requested. If the requested uri is "/rest/foo" then a template
*   named "foo.ftl" is searched for.
*   <li>The class of the object being serialized. If an object of org.acme.Foo is
*   being serialized then a template named "Foo.ftl" is searched for.
* </ol>
* </p>
* <p>
* <h2>Template Variables</h2>
* Variables provided to the template are created via reflection on the object
* being serialized and placed into a map called "properties". For instance consider
* the following class of object:
* <pre>
* class MyObject {
*
*   String getFoo();
*  
*   Integer getBar();
* }
* </pre>
* In the template values for the properties "foo" and "bar" would be available via:
* <pre>
* ${properties.foo}
* ${properties.bar}
* </pre>
* </p>
* <p>
* A variable called "page" is also provided which contains information about the resource being
* accessed. See {@link #createPageDetails(Request)} for more details.
* </p>
* <p>
* <h2>Reflection</h2>
* The template data model is created reflectively via the {@link ObjectToMapWrapper} class. This
* class can be extended to provide custom properties. See the javadoc for more details.
* </p>
*
* @author Justin Deoliveira, OpenGEO
*
*/
public class ReflectiveHTMLFormat extends DataFormat {
   
    private static final Logger LOGGER = Logging.getLogger("org.geoserver.rest");

    /**
     * The request/response being serviced
     */
    Request request;
    Response response;
   
    /**
     * The resource
     */
    Resource resource;
   
    /**
     * The class used for reflection
     */
    protected Class clazz;

    /**
     * Creates a new instance of the format.
     */
    public ReflectiveHTMLFormat(Request request,Response response,Resource resource) {
        this(null,request,response,resource);
    }

    /**
     * Creates a new instance of the format specifying the type of object being serialized.
     * <p>
     * This constructor is useful when reflection should be executed against an interface as opposed
     * to the concrete class of object being serialized.
     * </p>
     */
    public ReflectiveHTMLFormat( Class clazz, Request request,Response response, Resource resource ) {
        super( MediaType.TEXT_HTML );
        this.clazz = clazz;
        this.request = request;
        this.resource = resource;
    }
   
    @Override
    public Representation toRepresentation(Object object) {
  
        Class clazz = this.clazz != null ? this.clazz : object.getClass();
        Configuration configuration = createConfiguration(object, clazz);
        final ObjectWrapper wrapper = configuration.getObjectWrapper();
        configuration.setObjectWrapper(new ObjectWrapper() {
            public TemplateModel wrap(Object obj) throws TemplateModelException {
                TemplateModel model = wrapper.wrap(obj);
                if ( model instanceof SimpleHash ) {
                    SimpleHash hash = (SimpleHash) model;
                    if ( hash.get( "page" ) == null ) {
                        PageInfo pageInfo = (PageInfo) request.getAttributes().get( PageInfo.KEY );
                        if ( pageInfo != null ) {
                            hash.put( "page", pageInfo );   
                        }
                    }
                }
                return model;
            }
        });
       
        Template template = null;
       
        //first try finding a name directly
        String templateName = getTemplateName( object );
        if ( templateName != null ) {
            template = tryLoadTemplate(configuration, templateName);
            if(template == null)
                template = tryLoadTemplate(configuration, templateName + ".ftl");
        }
       
        //next look up by the resource being requested
        if ( template == null && request != null ) {
            //could not find a template bound to the class directly, search by the resource
            // being requested
            String r = request.getResourceRef().getLastSegment();
            if(r.equals(""))
                r = request.getResourceRef().getBaseRef().getLastSegment();
            int i = r.lastIndexOf( "." );
            if ( i != -1 ) {
                r = r.substring( 0, i );
            }
           
            template = tryLoadTemplate(configuration, r + ".ftl");
        }
       
        //finally try to find by class
        while( template == null && clazz != null ) {
            template = tryLoadTemplate(configuration, clazz.getSimpleName() + ".ftl");
            if(template == null) {
                for ( Class interfaze : clazz.getInterfaces() ) {
                    template = tryLoadTemplate(configuration, interfaze.getSimpleName() + ".ftl" );
                    if(template != null)
                        break;
                }
            }
           
            //move up the class hierachy to continue to look for a matching template
            if ( clazz.getSuperclass() == Object.class ) {
                break;
            }
            clazz = clazz.getSuperclass();
        }
       
        if ( template != null ) {
            templateName = template.getName();
        }
        else {
            //use a fallback
            templateName = "Object.ftl";
        }
       
        return new TemplateRepresentation( templateName, configuration, object, getMediaType() );
    }
   
    /**
     * Tries to load a template, will return null if it's not found. If the template exists
     * but it contains syntax errors an exception will be thrown instead
     *
     * @param configuration The template configuration.
     * @param templateName The name of the template to load.
     */
    protected Template tryLoadTemplate(Configuration configuration, String templateName) {
        try {
            return configuration.getTemplate(templateName);
        } catch(ParseException e) {
            throw new RuntimeException(e);
        } catch(IOException io) {
            LOGGER.log(Level.FINE, "Failed to lookup template " + templateName, io);
            return null;
        }
    }

    protected Configuration createConfiguration(Object data, Class clazz) {
        Configuration cfg = new Configuration( );
        cfg.setObjectWrapper( new ObjectToMapWrapper( clazz ));
        cfg.setClassForTemplateLoading(ReflectiveHTMLFormat.class,"");
       
        return cfg;
    }

    /**
     * @throws UnsupportedOperationException
     */
    public Object readRepresentation(Representation representation) {
        throw new UnsupportedOperationException( "Reading not implemented.");
    }

    /**
     * A hook into the template look-up mechanism.
     * <p>
     * This implementation returns null but subclasses may overide to explicitly specify the name
     * of the template to be used.
     * </p>
     * @param data The object being serialized.
     */
    protected String getTemplateName( Object data ) {
        return null;
    }

    /**
     * Wraps the object being serialized in a {@link SimpleHash} template model.
     * <p>
     * The method {@link #wrapInternal(Map, SimpleHash, Object)} may be overriden to customize
     * the returned model.
     * </p>
     */
    protected class ObjectToMapWrapper<T> extends BeansWrapper {

        /**
         * The class of object being serialized.
         */
        Class<T> clazz;

        public ObjectToMapWrapper( Class<T> clazz ) {
            this.clazz = clazz;
        }

        @Override
        public TemplateModel wrap(Object object) throws TemplateModelException {
            if ( object instanceof Collection ) {
                Collection c = (Collection) object;
                if (!c.isEmpty() ) {
                    Object o = c.iterator().next();
                    if ( clazz.isAssignableFrom( o.getClass() ) ) {
                        SimpleHash hash = new SimpleHash();
                        hash.put( "values", new CollectionModel( c, this ) );
                        return hash;
                    }   
                }
            }
           
            if ( object != null && clazz.isAssignableFrom( object.getClass() ) ) {
                HashMap map = new HashMap();
               
                ClassProperties cp = OwsUtils.getClassProperties(clazz);
                for ( String p : cp.properties() ) {
                    if ( "Class".equals( p ) ) continue;
                    Object value = OwsUtils.get(object, p);
                    if ( value == null ) {
                        value = "null";
                    }
                   
                    map.put( Character.toLowerCase(p.charAt(0)) + p.substring(1), value.toString());   
                   
                }
          
                SimpleHash model = new SimpleHash();
                model.put( "properties", new MapModel(map, this) );
                model.put( "className", clazz.getSimpleName() );
               
                wrapInternal(map, model, (T) object);
                return model;
            }
           
            return super.wrap(object);
        }

        /**
         * Template method to customize the returned template model.
         *
         * @param properties A map of properties obtained reflectively from the object being
         * serialized.
         * @param model The resulting template model.
         * @param object The object being serialized.
         */
        protected void wrapInternal(Map properties, SimpleHash model, T object ) {
        }

    }

}
TOP

Related Classes of org.geoserver.rest.format.ReflectiveHTMLFormat$ObjectToMapWrapper

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.