Changeset 3563

Show
Ignore:
Timestamp:
28/01/08 21:21:54 (4 years ago)
Author:
michael
Message:

Support for entity collections and lots of docs.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/src/main/java/org/sarugo/restlet/jpa/EntityCollection.java

    r3539 r3563  
    1 /** 
    2  * Copyright 2007 Sarugo Pty. Ltd.  
     1/* 
     2 * Copyright 2007, 2008 Sarugo Pty Ltd  
    33 *  
    44 * Licensed under the Common Development and Distribution License, 
     
    1717package org.sarugo.restlet.jpa; 
    1818 
    19 import java.lang.reflect.Field; 
    20 import java.lang.reflect.InvocationTargetException; 
    21 import java.lang.reflect.Method; 
    2219import java.util.ArrayList; 
    2320import java.util.List; 
    24 import java.util.Map; 
    25 import java.util.logging.Level; 
    2621 
    27 import javax.persistence.Id; 
    2822import javax.persistence.Query; 
    2923 
    3024import org.restlet.data.Parameter; 
    31 import org.restlet.data.Reference; 
    3225import org.restlet.data.Request; 
    3326import org.restlet.data.Response; 
     
    3528import org.restlet.resource.Representation; 
    3629import org.restlet.resource.Resource; 
     30import org.restlet.resource.ResourceException; 
    3731import org.restlet.resource.Variant; 
    38 import org.sarugo.restlet.jpa.converter.ConverterHelper; 
     32import org.sarugo.restlet.jpa.converter.InputConverter; 
     33import org.sarugo.restlet.jpa.converter.OutputConverter; 
    3934 
    4035/** 
    41  * A resource which maps to a JPA entity. The behaviour of this class is largely 
    42  * controlled by the {@link EntityFinder} which creates it. 
     36 * A resource which maps to a collection of JPA entities. The behaviour of this 
     37 * class is largely controlled by the {@link EntityFinder} which creates it. 
    4338 *  
    44  * @author michael 
     39 * @author Michael Terrington 
    4540 */ 
    4641public class EntityCollection<E> extends Resource { 
    4742 
    48         /** 
    49          * Add a {@link Map} to the request attributes ({@link Request#getAttributes()}) 
    50          * with this name to add parameters to the JPA query. 
    51          */ 
    52         public static final String QUERY_PARAMS_ATTRIBUTE = "org.sarugo.restlet.jpa.QueryParams"; 
     43    private final EntityFinder<E> finder; 
    5344 
    54        private PersistenceRouter router
     45    protected final List<E> entityList
    5546 
    56        protected ResourceInfo info
     47    protected final int start
    5748 
    58        protected E entity
     49    protected final int maxResults
    5950 
    60        protected List<? extends Object> entities
     51    protected final boolean listComplete
    6152 
    62         protected int start; 
     53    public EntityCollection(EntityFinder<E> finder, Request request, 
     54            Response response) { 
     55        super(finder.getContext(), request, response); 
     56        this.finder = finder; 
     57        int start = 1; 
     58        int maxResults = finder.getMaxResults(); 
     59        for (Parameter param : getRequest().getResourceRef().getQueryAsForm()) { 
     60            if (param.getName().equals("max")) { 
     61                // Set max to minimum of the finder's limit or request value 
     62                // This prevents DoS consumption of resources 
     63                maxResults = Math.min(Integer.parseInt(param.getValue()), 
     64                        maxResults); 
     65            } else if (param.getName().equals("start")) { 
     66                start = Integer.parseInt(param.getValue()); 
     67            } 
     68        } 
     69        this.start = start; 
     70        this.maxResults = maxResults; 
     71        Query q = finder.getEntityListQuery(request, response); 
     72        q.setFirstResult(start - 1); 
     73        q.setMaxResults(maxResults + 1); 
     74        @SuppressWarnings("unchecked") 
     75        // Copy list to workaround OpenJPA lack of support for subList() 
     76        List<E> entities = new ArrayList(q.getResultList()); 
     77        listComplete = (entities.size() <= maxResults); 
     78        // truncate if the list is more than max results was returned 
     79        if (!listComplete) { 
     80            entities = entities.subList(0, maxResults); 
     81        } 
     82        entityList = entities; 
     83    } 
    6384 
    64         protected int maxResults; 
     85    public List<E> getEntityList() { 
     86        return entityList; 
     87    } 
    6588 
    66         protected boolean listComplete; 
     89    public boolean isListComplete() { 
     90        return listComplete; 
     91    } 
    6792 
    68         public EntityCollection(PersistenceRouter router, Request request, 
    69                         Response response, ResourceInfo ri) { 
    70                 super(router.getContext(), request, response); 
    71                 this.router = router; 
    72                 this.info = ri; 
    73                 this.start = 1; 
    74                 this.maxResults = ri.getMaxResults(); 
    75                 initEntity(); 
    76                 initEntityList(); 
    77                 if (entity != null) { 
    78                         for (ConverterHelper converter : info.getConverters()) { 
    79                                 converter.initEntityVariants(this); 
    80                         } 
    81                 } else { 
    82                         for (ConverterHelper converter : info.getConverters()) { 
    83                                 converter.initEntityListVariants(this); 
    84                         } 
    85                 } 
    86         } 
     93    public int getMaxResults() { 
     94        return maxResults; 
     95    } 
    8796 
    88         protected void initEntity() { 
    89                 String id = (String) getRequest().getAttributes().get("id"); 
    90                 if (id != null) { 
    91                         entity = router.getEntityManager().find(info.getModel(), 
    92                                         getAsIdType(id)); 
    93                         if (entity == null) { 
    94                                 getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND); 
    95                         } 
    96                 } 
    97         } 
     97    public int getStart() { 
     98        return start; 
     99    } 
    98100 
    99         @SuppressWarnings("unchecked") 
    100         protected void initEntityList() { 
    101                 // List of entities 
    102                 StringBuilder search = null; 
    103                 String searchValue = null; 
    104                 for (Parameter param : getRequest().getResourceRef().getQueryAsForm()) { 
    105                         if (param.getName().equals("max")) { 
    106                                 maxResults = Integer.parseInt(param.getValue()); 
    107                         } else if (param.getName().equals("start")) { 
    108                                 start = Integer.parseInt(param.getValue()); 
    109                         } else if (param.getName().equals("q") 
    110                                         && info.getListSearchFields() != null) { 
    111                                 search = new StringBuilder(); 
    112                                 for (String field : info.getListSearchFields()) { 
    113                                         if (search.length() > 0) { 
    114                                                 search.append(" OR "); 
    115                                         } 
    116                                         search.append("o."); 
    117                                         search.append(field); 
    118                                         search.append(" LIKE :searchValue"); 
    119                                 } 
    120                                 searchValue = "%" + param.getValue() + "%"; 
    121                         } 
    122                 } 
    123                 StringBuilder sb = new StringBuilder(); 
    124                 sb.append("SELECT o FROM "); 
    125                 sb.append(info.getModel().getSimpleName()); 
    126                 sb.append(" o"); 
    127                 if (info.getListJoin() != null && info.getListJoin().length() > 0) { 
    128                         sb.append(" "); 
    129                         sb.append(info.getListJoin()); 
    130                 } 
    131                 if (info.getListWhere() != null && info.getListWhere().length() > 0) { 
    132                         sb.append(" WHERE "); 
    133                         sb.append(info.getListWhere()); 
    134                         if (search != null && searchValue != null) { 
    135                                 sb.append(" AND ("); 
    136                                 sb.append(search); 
    137                                 sb.append(")"); 
    138                         } 
    139                 } else if (search != null && searchValue != null) { 
    140                         sb.append(" WHERE "); 
    141                         sb.append(search); 
    142                 } 
    143                 if (info.getListOrder() != null && info.getListOrder().length() > 0) { 
    144                         sb.append(" ORDER BY "); 
    145                         sb.append(info.getListOrder()); 
    146                 } 
    147                 Query q = router.getEntityManager().createQuery(sb.toString()); 
    148                 Map<String, Object> queryParams = (Map<String, Object>) getRequest() 
    149                                 .getAttributes().get(QUERY_PARAMS_ATTRIBUTE); 
    150                 if (queryParams != null) { 
    151                         for (Map.Entry<String, Object> param : queryParams.entrySet()) { 
    152                                 q.setParameter(param.getKey(), param.getValue()); 
    153                         } 
    154                 } 
    155                 if (search != null && searchValue != null) { 
    156                         q.setParameter("searchValue", searchValue); 
    157                 } 
    158                 q.setFirstResult(start - 1); 
    159                 q.setMaxResults(maxResults + 1); 
    160                 entities = new ArrayList(q.getResultList()); // workaround OpenJPA 
    161                 listComplete = (entities.size() <= maxResults); 
    162                 // truncate if the list is more than max results was returned 
    163                 if (!listComplete) { 
    164                         entities = entities.subList(0, maxResults); 
    165                 } 
    166         } 
     101    public EntityFinder<E> getFinder() { 
     102        return finder; 
     103    } 
    167104 
    168         @Override 
    169         public Representation getRepresentation(Variant variant) { 
    170                 Representation result = null; 
    171                 if (variant instanceof Representation) { 
    172                         result = (Representation) variant; 
    173                 } else if (entity != null) { 
    174                         for (ConverterHelper converter : info.getConverters()) { 
    175                                 result = converter.getEntityRepresentation(variant, this); 
    176                                 if (result != null) 
    177                                         break; 
    178                         } 
    179                 } else { 
    180                         for (ConverterHelper converter : info.getConverters()) { 
    181                                 result = converter.getEntityListRepresentation(variant, this); 
    182                                 if (result != null) 
    183                                         break; 
    184                         } 
    185                 } 
    186                 return result; 
    187         } 
     105    @Override 
     106    public boolean allowPost() { 
     107        return !getFinder().getInputConverters().isEmpty(); 
     108    } 
    188109 
    189         public String getEntityURI(Object entity) { 
    190                 Reference ref = getEntityReference(entity); 
    191                 if (ref != null) { 
    192                         return ref.getRelativeRef(getRequest().getResourceRef()).toString(); 
    193                 } else { 
    194                         return null; 
    195                 } 
    196         } 
     110    @Override 
     111    public boolean isReadable() { 
     112        return !getFinder().getOutputConverters().isEmpty(); 
     113    } 
    197114 
    198         public Reference getEntityReference(Object entity) { 
    199                 String entityPath = getRequest().getResourceRef() 
    200                                 .toString(false, false); 
    201                 if (!entityPath.endsWith("/")) { 
    202                         entityPath = entityPath.substring(0, 
    203                                         entityPath.lastIndexOf("/") + 1); 
    204                 } 
    205                 if (!getModel().isInstance(entity)) { 
    206                         String name = getRouter().getName(entity.getClass()); 
    207                         if (name == null) { 
    208                                 getLogger().warning( 
    209                                                 "Attempt to get reference for unknown entity type: " 
    210                                                                 + entity.getClass()); 
    211                                 return null; 
    212                         } 
    213                         entityPath += "../" + name + "/"; 
    214                 } 
    215                 String entityId = getIdForEntity(entity); 
    216                 if (entityId != null) { 
    217                         return new Reference(entityPath + entityId).normalize(); 
    218                 } else { 
    219                         return null; 
    220                 } 
    221         } 
     115    @Override 
     116    public Representation represent(Variant variant) throws ResourceException { 
     117        Representation representation = null; 
     118        for (OutputConverter<E> converter : getFinder().getOutputConverters()) { 
     119            representation = converter.represent(this, variant); 
     120            if (representation != null) { 
     121                break; 
     122            } 
     123        } 
     124        return representation; 
     125    } 
    222126 
    223         public String getIdForEntity(Object entity) { 
    224                 if (entity != null) { 
    225                         for (Field f : entity.getClass().getDeclaredFields()) { 
    226                                 if (f.isAnnotationPresent(Id.class)) { 
    227                                         f.setAccessible(true); 
    228                                         try { 
    229                                                 return String.valueOf(f.get(entity)); 
    230                                         } catch (IllegalArgumentException e) { 
    231                                                 getLogger().log(Level.WARNING, 
    232                                                                 "Unable to get Id for object", e); 
    233                                         } catch (IllegalAccessException e) { 
    234                                                 getLogger().log(Level.WARNING, 
    235                                                                 "Unable to get Id for object", e); 
    236                                         } 
    237                                 } 
    238                         } 
    239                         for (Method m : entity.getClass().getDeclaredMethods()) { 
    240                                 if (m.isAnnotationPresent(Id.class)) { 
    241                                         m.setAccessible(true); 
    242                                         try { 
    243                                                 return String.valueOf(m.invoke(entity)); 
    244                                         } catch (IllegalArgumentException e) { 
    245                                                 getLogger().log(Level.WARNING, 
    246                                                                 "Unable to get Id for object", e); 
    247                                         } catch (IllegalAccessException e) { 
    248                                                 getLogger().log(Level.WARNING, 
    249                                                                 "Unable to get Id for object", e); 
    250                                         } catch (InvocationTargetException e) { 
    251                                                 getLogger().log(Level.WARNING, 
    252                                                                 "Unable to get Id for object", e); 
    253                                         } 
    254                                 } 
    255                         } 
    256                 } 
    257                 return null; 
    258         } 
    259  
    260         protected Object getAsIdType(String value) { 
    261                 return getAsIdType(getModel(), value); 
    262         } 
    263  
    264         public static Object getAsIdType(Class<? extends Object> model, String value) { 
    265                 Class<? extends Object> type = String.class; 
    266                 for (Field f : model.getDeclaredFields()) { 
    267                         if (f.isAnnotationPresent(Id.class)) { 
    268                                 type = f.getType(); 
    269                         } 
    270                 } 
    271                 for (Method m : model.getDeclaredMethods()) { 
    272                         if (m.isAnnotationPresent(Id.class)) { 
    273                                 type = m.getReturnType(); 
    274                         } 
    275                 } 
    276                 return ConverterHelper.convertToType(type, value, null); 
    277         } 
    278  
    279         public List<? extends Object> getEntities() { 
    280                 return entities; 
    281         } 
    282  
    283         public Object getEntity() { 
    284                 return entity; 
    285         } 
    286  
    287         public boolean isListComplete() { 
    288                 return listComplete; 
    289         } 
    290  
    291         public int getMaxResults() { 
    292                 return maxResults; 
    293         } 
    294  
    295         public Class<? extends Object> getModel() { 
    296                 return info.getModel(); 
    297         } 
    298  
    299         public String getName() { 
    300                 return info.getName(); 
    301         } 
    302  
    303         public PersistenceRouter getRouter() { 
    304                 return router; 
    305         } 
    306  
    307         public int getStart() { 
    308                 return start; 
    309         } 
    310  
    311         @Override 
    312         public boolean allowDelete() { 
    313                 return !info.isReadOnly() && entity != null; 
    314         } 
    315  
    316         @Override 
    317         public boolean allowPost() { 
    318                 return !info.isReadOnly() && entity == null; 
    319         } 
    320  
    321         @Override 
    322         public boolean allowPut() { 
    323                 return !info.isReadOnly() && entity != null; 
    324         } 
    325  
    326         @Override 
    327         public void handleDelete() { 
    328                 getRouter().getEntityManager().remove(entity); 
    329                 getRouter().getEntityManager().flush(); 
    330         } 
    331  
    332         @Override 
    333         public void handlePost() { 
    334                 try { 
    335                         entity = getModel().newInstance(); 
    336                         updateBean(entity); 
    337                 } catch (IllegalAccessException e) { 
    338                         getLogger().log(Level.WARNING, "Unable to create entity.", e); 
    339                         getResponse().setStatus(Status.SERVER_ERROR_INTERNAL); 
    340                 } catch (InstantiationException e) { 
    341                         getLogger().log(Level.WARNING, "Unable to create entity.", e); 
    342                         getResponse().setStatus(Status.SERVER_ERROR_INTERNAL); 
    343                 } 
    344                 if (getResponse().getStatus().isSuccess()) { 
    345                         getRouter().getEntityManager().persist(entity); 
    346                         getRouter().getEntityManager().flush(); 
    347                         getResponse().setStatus(Status.SUCCESS_CREATED); 
    348                         getResponse().setRedirectRef(getEntityReference(entity)); 
    349                 } 
    350         } 
    351  
    352         protected void updateBean(Object bean) { 
    353                 for (ConverterHelper converter : info.getConverters()) { 
    354                         if (converter.updateEntity(bean, this)) { 
    355                                 break; 
    356                         } 
    357                 } 
    358         } 
    359  
    360         @Override 
    361         public void handlePut() { 
    362                 updateBean(entity); 
    363                 if (getResponse().getStatus().isSuccess()) { 
    364             getRouter().getEntityManager().flush(); 
    365                         getResponse().setEntity(getPreferredRepresentation()); 
    366                 } 
    367         } 
    368  
    369         public boolean isReadOnly() { 
    370                 return info.isReadOnly(); 
    371         } 
     127    @Override 
     128    public void acceptRepresentation(Representation representation) 
     129            throws ResourceException { 
     130        boolean accepted = false; 
     131        for (InputConverter<E> converter : getFinder().getInputConverters()) { 
     132            E entity = converter.acceptRepresentation(representation); 
     133            if (entity != null) { 
     134                getFinder().getRouter().getEntityManager().persist(entity); 
     135                accepted = true; 
     136                break; 
     137            } 
     138        } 
     139        if (!accepted) { 
     140            getResponse().setStatus(Status.CLIENT_ERROR_UNSUPPORTED_MEDIA_TYPE); 
     141        } 
     142    } 
    372143 
    373144} 
  • trunk/src/main/java/org/sarugo/restlet/jpa/EntityFinder.java

    r3539 r3563  
     1/* 
     2 * Copyright 2007, 2008 Sarugo Pty Ltd  
     3 *  
     4 * Licensed under the Common Development and Distribution License, 
     5 * you may not use this file except in compliance with the License. 
     6 * You may obtain a copy of the License at 
     7 *  
     8 *   http://www.sun.com/cddl/ 
     9 *    
     10 * Unless required by applicable law or agreed to in writing, software 
     11 * distributed under the License is distributed on an "AS IS" BASIS, 
     12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or  
     13 * implied. See the License for the specific language governing 
     14 * permissions and limitations under the License. 
     15 */ 
     16 
    117package org.sarugo.restlet.jpa; 
    218 
     
    1026import java.util.logging.Level; 
    1127 
     28import javax.persistence.EntityManager; 
    1229import javax.persistence.Id; 
     30import javax.persistence.Query; 
    1331 
    1432import org.restlet.Finder; 
     
    1735import org.restlet.data.Request; 
    1836import org.restlet.data.Response; 
     37import org.restlet.resource.Resource; 
    1938import org.sarugo.restlet.jpa.converter.ConverterHelper; 
    2039import org.sarugo.restlet.jpa.converter.InputConverter; 
    2140import org.sarugo.restlet.jpa.converter.OutputConverter; 
    2241 
     42/** 
     43 * An entity finder maps a request to either an {@link EntityResource} (for 
     44 * entity instances) or {@link EntityCollection} (for entity collections). 
     45 * Conversions for request processing are performed by 
     46 * {@link InputConverter input} and {@link OutputConverter output} converters. 
     47 *  
     48 * @author Michael Terrington 
     49 *  
     50 * @param <E> 
     51 *            The entity type. 
     52 */ 
    2353public class EntityFinder<E> extends Finder { 
    2454 
     
    3565    private Route route; 
    3666 
    37     public EntityFinder(PersistenceRouter router, Class<E> entityClass) { 
    38         super(router.getContext(), EntityResource.class); 
     67    private final List<Route> aliases; 
     68 
     69    private int maxResults; 
     70 
     71    /** 
     72     * Creates an entity finder. 
     73     *  
     74     * @param router 
     75     *            The {@link PersistenceRouter} this finder will be be attached 
     76     *            to. 
     77     * @param entityClass 
     78     *            The entity class this finder operates on. 
     79     * @param resource 
     80     *            Either {@link EntityResource} or {@link EntityCollection} or a 
     81     *            sub-class. Sub-classes must have a constructor: 
     82     *            {@link EntityFinder}, {@link Request}, {@link Response}. 
     83     */ 
     84    public EntityFinder(PersistenceRouter router, Class<E> entityClass, 
     85            Class<? extends Resource> resource) { 
     86        super(router.getContext(), resource); 
    3987        this.router = router; 
    4088        this.entityClass = entityClass; 
    41         this.entityIdClass = findIdType(); 
     89        this.entityIdClass = EntityHelper.findIdType(entityClass); 
    4290        this.inputConverters = new ArrayList<InputConverter<E>>(); 
    4391        this.outputConverters = new ArrayList<OutputConverter<E>>(); 
    44     } 
    45  
     92        this.aliases = new ArrayList<Route>(); 
     93    } 
     94 
     95    /** Get the {@link PersistenceRouter} this finder is attached to. */ 
    4696    public PersistenceRouter getRouter() { 
    4797        return router; 
    4898    } 
    4999 
     100    /** Get the route this finder is attached to. */ 
    50101    public Route getRoute() { 
    51102        return route; 
    52103    } 
    53104 
    54     public void setRoute(Route route) { 
     105    /** 
     106     * Attach this finder to a router. Should only be called by 
     107     * {@link PersistenceRouter}. 
     108     *  
     109     * @see PersistenceRouter#attach(String, EntityFinder) 
     110     * @see PersistenceRouter#attachCollection(String, EntityFinder) 
     111     */ 
     112    void setRoute(Route route) { 
    55113        if (this.route != null) { 
    56114            throw new IllegalStateException("Route already set."); 
     
    59117    } 
    60118 
     119    /** Get a list of additional routes this finder is associated with. */ 
     120    public List<Route> getAliases() { 
     121        return aliases; 
     122    } 
     123 
     124    /** Get the entity class this finder is associated with. */ 
    61125    public Class<E> getEntityClass() { 
    62126        return entityClass; 
    63127    } 
    64128 
     129    /** Get the list of input converters. */ 
    65130    public List<InputConverter<E>> getInputConverters() { 
    66131        return inputConverters; 
    67132    } 
    68133 
     134    /** Add an input converter. Returns this finder to enable call chaining. */ 
     135    public EntityFinder<E> addInputConverter(InputConverter<E> inputConverter) { 
     136        inputConverters.add(inputConverter); 
     137        return this; 
     138    } 
     139 
     140    /** Get the list of output converters. */ 
    69141    public List<OutputConverter<E>> getOutputConverters() { 
    70142        return outputConverters; 
    71143    } 
    72144 
     145    /** Add an output converter. Returns this finder to enable call chaining. */ 
     146    public EntityFinder<E> addOutputConverter(OutputConverter<E> outputConverter) { 
     147        outputConverters.add(outputConverter); 
     148        return this; 
     149    } 
     150 
     151    /** 
     152     * Constructs the associated resource target, invoking the 
     153     * {@link EntityFinder}, {@link Request}, {@link Response} constructor. 
     154     */ 
    73155    @Override 
    74156    protected Handler findTarget(Request request, Response response) { 
     
    93175    } 
    94176 
     177    /** 
     178     * Convert an id string to an object suitable for passing to 
     179     * {@link EntityManager#find(Class, Object)}. For simple entity id's the 
     180     * default implementation should suffice. Entity's with compound identity 
     181     * objects should override this method. 
     182     *  
     183     * @param value 
     184     *            The id string. 
     185     * @return The identity object. 
     186     */ 
    95187    public Object convertIdString(String value) { 
    96188        return ConverterHelper.convertToType(entityIdClass, value, null); 
    97189    } 
    98190 
     191    /** 
     192     * Get the id string for a given entity. For simple entity id's the default 
     193     * implementation should suffice. Entity's with compound identity objects 
     194     * should override this method. 
     195     *  
     196     * @param entity 
     197     *            The entity. 
     198     * @return The id string. 
     199     */ 
    99200    public String getIdString(E entity) { 
    100201        if (entity != null) { 
     
    134235    } 
    135236 
     237    /** 
     238     * Get a the attached URL for a given entity. The default implementation 
     239     * applies the URL template in the {@link #getRoute() attached route} with 
     240     * parameter "id" and the result of {@link #getIdString(Object)}. 
     241     *  
     242     * @param entity 
     243     *            The entity. 
     244     * @return The URL relative to the attached {@link PersistenceRouter}. 
     245     */ 
    136246    public String getEntityURL(E entity) { 
    137247        return route.getTemplate().format( 
     
    139249    } 
    140250 
    141     public E findEntity(Request request, Response response) { 
    142         return findEntity((String) request.getAttributes().get("id")); 
    143     } 
    144  
    145     public E findEntity(String id) { 
     251    /** 
     252     * Get the entity identified by the request URL. By default this invokes 
     253     * {@link #getEntity(String)} with id string retrieved from the request 
     254     * parameter "id". 
     255     */ 
     256    public E getEntity(Request request, Response response) { 
     257        return getEntity((String) request.getAttributes().get("id")); 
     258    } 
     259 
     260    /** 
     261     * Get the entity identified by the id string. Invokes 
     262     * {@link EntityManager#find(Class, Object)} with the result of 
     263     * {@link #convertIdString(String)}. 
     264     *  
     265     * @param id 
     266     *            The id string. 
     267     * @return The entity or null if not found. 
     268     */ 
     269    public E getEntity(String id) { 
    146270        E entity = null; 
    147271        if (id != null) { 
     
    152276    } 
    153277 
     278    /** 
     279     * Removes an entity from persistence. 
     280     *  
     281     * @param entity 
     282     *            The entity to remove. 
     283     * @return true if the entity was removed. 
     284     */ 
    154285    public boolean removeEntity(E entity) { 
    155286        router.getEntityManager().remove(entity); 
     
    157288    } 
    158289 
    159     private Class<? extends Object> findIdType() { 
    160         Class<? extends Object> type = null; 
    161         for (Field f : entityClass.getDeclaredFields()) { 
    162             if (f.isAnnotationPresent(Id.class)) { 
    163                 if (type == null) { 
    164                     type = f.getType(); 
    165                 } else { 
    166                     // compound keys default to string type 
    167                     type = String.class; 
    168                 } 
    169             } 
    170         } 
    171         for (Method m : entityClass.getDeclaredMethods()) { 
    172             if (m.isAnnotationPresent(Id.class)) { 
    173                 if (type == null) { 
    174                     type = m.getReturnType(); 
    175                 } else { 
    176                     // compound keys default to string type 
    177                     type = String.class; 
    178                 } 
    179             } 
    180         } 
    181         if (type == null) { 
    182             // no key found - default to string 
    183             type = String.class; 
    184         } 
    185         return type; 
     290    /** 
     291     * Get the query for the entity collection. If the request defines a 
     292     * parameter "queryName", that is used to call 
     293     * {@link #getEntityListQuery(String)}. Alternatively, 
     294     * {@link #getEntityListQuery()} is called to get the default query. 
     295     */ 
     296    public Query getEntityListQuery(Request request, Response response) { 
     297        String queryName = (String) request.getAttributes().get("queryName"); 
     298        if (queryName != null) { 
     299            return getEntityListQuery(queryName); 
     300        } else { 
     301            return getEntityListQuery(); 
     302        } 
     303    } 
     304 
     305    /** Get a named query. */ 
     306    protected Query getEntityListQuery(String queryName) { 
     307        return router.getEntityManager().createNamedQuery(queryName); 
     308    } 
     309 
     310    /** Get the default query. */ 
     311    protected Query getEntityListQuery() { 
     312        return router.getEntityManager().createQuery( 
     313                "SELECT o from " + EntityHelper.getEntityName(getEntityClass()) 
     314                        + " o"); 
     315    } 
     316 
     317    public int getMaxResults() { 
     318        return maxResults; 
     319    } 
     320 
     321    /** 
     322     * Set the maximum results that should be returned from a query. 
     323     * {@link EntityCollection} uses this to limit query results. 
     324     */ 
     325    public EntityFinder<E> setMaxResults(int maxResults) { 
     326        this.maxResults = maxResults; 
     327        if (this.maxResults == Integer.MAX_VALUE) { 
     328            this.maxResults--; 
     329        } 
     330        return this; 
    186331    } 
    187332} 
  • trunk/src/main/java/org/sarugo/restlet/jpa/EntityResource.java

    r3539 r3563  
    1 /** 
     1/* 
     2 * Copyright 2007, 2008 Sarugo Pty Ltd  
    23 *  
     4 * Licensed under the Common Development and Distribution License, 
     5 * you may not use this file except in compliance with the License. 
     6 * You may obtain a copy of the License at 
     7 *  
     8 *   http://www.sun.com/cddl/ 
     9 *    
     10 * Unless required by applicable law or agreed to in writing, software 
     11 * distributed under the License is distributed on an "AS IS" BASIS, 
     12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or  
     13 * implied. See the License for the specific language governing 
     14 * permissions and limitations under the License. 
    315 */ 
     16 
    417package org.sarugo.restlet.jpa; 
    518 
     
    1427import org.sarugo.restlet.jpa.converter.OutputConverter; 
    1528 
     29/** 
     30 * A resource which maps to a JPA entity. The behaviour of this class is largely 
     31 * controlled by the {@link EntityFinder} which creates it. 
     32 *  
     33 * @author Michael Terrington 
     34 */ 
    1635public class EntityResource<E> extends Resource { 
    1736 
     
    2443        super(finder.getContext(), request, response); 
    2544        this.finder = finder; 
    26         this.entity = finder.findEntity(request, response); 
     45        this.entity = finder.getEntity(request, response); 
    2746        for (OutputConverter<E> converter : finder.getOutputConverters()) { 
    2847            getVariants().addAll(converter.getVariants()); 
     
    7392    public void storeRepresentation(Representation representation) 
    7493            throws ResourceException { 
     94        boolean accepted = false; 
    7595        for (InputConverter<E> converter : getFinder().getInputConverters()) { 
    76             if (converter.storeRepresentation(this, representation)) 
    77                 ; 
     96            if (converter.storeRepresentation(getEntity(), representation)) { 
     97                accepted = true; 
     98                break; 
     99            } 
     100        } 
     101        if (!accepted) { 
     102            getResponse().setStatus(Status.CLIENT_ERROR_UNSUPPORTED_MEDIA_TYPE); 
    78103        } 
    79104    } 
  • trunk/src/main/java/org/sarugo/restlet/jpa/PersistenceRouter.java

    r3539 r3563  
    1 /** 
    2  * Copyright 2007 Sarugo Pty. Ltd.  
     1/* 
     2 * Copyright 2007, 2008 Sarugo Pty Ltd  
    33 *  
    44 * Licensed under the Common Development and Distribution License, 
     
    2121import java.util.logging.Level; 
    2222 
    23 import javax.persistence.Entity; 
    2423import javax.persistence.EntityManager; 
    2524import javax.persistence.EntityManagerFactory; 
     
    3635 
    3736/** 
    38  * Root of JPA entity mappings. 
    39  *  
    40  * @author michael 
     37 * Root of JPA entity mappings. All related entities and entity collections 
     38 * should share a common PersistenceRouter, this enables link resolution. 
     39 *  
     40 * {@link EntityFinder}s are attached to handle entity instances or 
     41 * collections. Instances are attached independently from collections. An 
     42 * {@link EntityFinder} can only be attached to one URL, however it may have 
     43 * several {@link #alias(String, EntityFinder) aliases}. 
     44 *  
     45 * <b>Known Issue:</b><br> 
     46 * Currently only a single PersistenceRouter is supported and it must be 
     47 * attached to the root of the URL-space due to the way 
     48 * {@link #getEntityURL(Object)} works. 
     49 *  
     50 * @author Michael Terrington 
    4151 */ 
    4252public class PersistenceRouter extends Restlet { 
     
    5060    private final Map<Class, EntityFinder> entities; 
    5161 
     62    /** 
     63     * Create a PersistenceRouter associated with an 
     64     * {@link EntityManagerFactory}. The {@link EntityManagerFactory} must 
     65     * manage any entity types associated with this PersistenceRouter. For each 
     66     * request handled an {@link EntityManager} will be created from the 
     67     * {@link EntityManagerFactory}. 
     68     *  
     69     * @param context 
     70     *            Restlet context for this PersistenceRouter. 
     71     * @param entityManagerFactory 
     72     *            The entity manager factory. 
     73     */ 
    5274    public PersistenceRouter(Context context, 
    5375            EntityManagerFactory entityManagerFactory) { 
     
    5981    } 
    6082 
     83    /** 
     84     * Get the {@link EntityManagerFactory} associated with this 
     85     * PersistenceRouter. 
     86     */ 
    6187    public EntityManagerFactory getEntityManagerFactory() { 
    6288        return entityManagerFactory; 
    6389    } 
    6490 
     91    /** 
     92     * Get a thread-local {@link EntityManager}. Typically during request 
     93     * processing an {@link EntityManager} is created and a transaction begun 
     94     * before passing control to an {@link EntityFinder}. During processing 
     95     * (which is always in the same thread), the {@link EntityFinder} can call 
     96     * this method to get the {@link EntityManager} associated with the request. 
     97     * After request processing is complete, the transaction is completed and 
     98     * the {@link EntityManager} closed and cleared from the thread-local. 
     99     */ 
    65100    public EntityManager getEntityManager() { 
    66101        EntityManager em = entityManager.get(); 
     
    72107    } 
    73108 
     109    /** 
     110     * Convert an entity to a URL based on an attached {@link EntityFinder}. 
     111     *  
     112     * @param entity 
     113     *            The entity to get a URL for. 
     114     * @return The entity's URL relative to this PersistenceRouter. 
     115     * @see #attach(String, EntityFinder) 
     116     */ 
    74117    @SuppressWarnings("unchecked") 
    75118    public String getEntityURL(Object entity) { 
     
    82125    } 
    83126 
     127    /** 
     128     * Handle a request by: 
     129     * <ol> 
     130     * <li>Creating an {@link EntityManager} and beginning a transaction.</li> 
     131     * <li>Sending the request to the {@link EntityFinder} which matches the 
     132     * request URL.</li> 
     133     * <li>Commiting (or rolling-back) the transaction and clearing the 
     134     * {@link EntityManager}.</li> 
     135     * </ol> 
     136     */ 
    84137    @Override 
    85138    public void handle(Request request, Response response) { 
     
    104157    } 
    105158 
     159    /** 
     160     * Attach an {@link EntityFinder} for handling {@link EntityResource}s. 
     161     * That is, a handler for entity instances, not the entity collection. 
     162     * Invokes {@link #attach(EntityFinder)} with a new {@link EntityFinder}. 
     163     *  
     164     * @param entityClass 
     165     *            The entity class to attach. 
     166     * @return The finder for the entity. 
     167     * @see #attachCollection(Class) for attaching an {@link EntityFinder} for 
     168     *      the entity collection. 
     169     */ 
    106170    public <E extends Object> EntityFinder<E> attach(Class<E> entityClass) { 
    107         return attach(new EntityFinder<E>(this, entityClass)); 
    108     } 
    109  
     171        return attach(new EntityFinder<E>(this, entityClass, 
     172                EntityResource.class)); 
     173    } 
     174 
     175    /** 
     176     * Attach an {@link EntityFinder} for handling {@link EntityResource}s. 
     177     * That is, a handler for entity instances, not the entity collection. 
     178     * Invokes {@link #attach(String, EntityFinder)} with the given 
     179     * {@link EntityFinder} and the URL "/{entityName}/{id}" where 
     180     * "{entityName}" is formed by calling 
     181     * {@link EntityHelper#getEntityName(Class)}. 
     182     *  
     183     * @param finder 
     184     *            The entity finder to attach. 
     185     * @return The finder for the entity. 
     186     * @throws IllegalStateException 
     187     *             If the finder has already been attached. 
     188     * @see #attachCollection(EntityFinder) for attaching an 
     189     *      {@link EntityFinder} for the entity collection. 
     190     */ 
    110191    public <E extends Object> EntityFinder<E> attach(EntityFinder<E> finder) { 
    111         return attach("/" + createName(finder.getEntityClass()) + "/{id}", 
    112                 finder); 
    113     } 
    114  
     192        return attach("/" + EntityHelper.getEntityName(finder.getEntityClass()) 
     193                + "/{id}", finder); 
     194    } 
     195 
     196    /** 
     197     * Attach an {@link EntityFinder} for handling {@link EntityResource}s. 
     198     * That is, a handler for entity instances, not the entity collection. 
     199     * Invokes {@link #attach(String, EntityFinder)} with a new 
     200     * {@link EntityFinder}. 
     201     *  
     202     * @param uriPattern 
     203     *            The URL pattern to attach the {@link EntityFinder} at. By 
     204     *            default, {@link EntityFinder#getEntity(Request, Response)} 
     205     *            expects the URL to contain "{id}" to define the entity id. 
     206     * @param entityClass 
     207     *            The entity class to attach. 
     208     * @return The finder for the entity. 
     209     * @see #attachCollection(String, Class)) for attaching an 
     210     *      {@link EntityFinder} for the entity collection. 
     211     */ 
    115212    public <E extends Object> EntityFinder<E> attach(String uriPattern, 
    116213            Class<E> entityClass) { 
    117         return attach(uriPattern, new EntityFinder<E>(this, entityClass)); 
    118     } 
    119  
     214        return attach(uriPattern, new EntityFinder<E>(this, entityClass, 
     215                EntityResource.class)); 
     216    } 
     217 
     218    /** 
     219     * Attach an {@link EntityFinder} for handling {@link EntityResource}s. 
     220     * That is, a handler for entity instances, not the entity collection. 
     221     *  
     222     * @param uriPattern 
     223     *            The URL pattern to attach the {@link EntityFinder} at. By 
     224     *            default, {@link EntityFinder#getEntity(Request, Response)} 
     225     *            expects the URL to contain "{id}" to define the entity id. 
     226     * @param finder 
     227     *            The entity finder to attach. 
     228     * @return The finder for the entity. 
     229     * @throws IllegalStateException 
     230     *             If the finder has already been attached. 
     231     * @see #attachCollection(String, EntityFinder)) for attaching an 
     232     *      {@link EntityFinder} for the entity collection. 
     233     */ 
    120234    public <E extends Object> EntityFinder<E> attach(String uriPattern, 
    121235            EntityFinder<E> finder) { 
     
    129243    } 
    130244 
    131     public Route alias(String uriPattern, EntityFinder finder) { 
     245    /** 
     246     * Attach an {@link EntityFinder} for handling {@link EntityCollection}s. 
     247     * That is, a handler for an entity collection, not entity instances. 
     248     * Invokes {@link #attachCollection(EntityFinder)} with a new 
     249     * {@link EntityFinder}. 
     250     *  
     251     * @param entityClass 
     252     *            The entity class to attach. 
     253     * @return The finder for the entity. 
     254     */ 
     255    public <E extends Object> EntityFinder<E> attachCollection( 
     256            Class<E> entityClass) { 
     257        return attachCollection(new EntityFinder<E>(this, entityClass, 
     258                EntityCollection.class)); 
     259    } 
     260 
     261    /** 
     262     * Attach an {@link EntityFinder} for handling {@link EntityCollection}s. 
     263     * That is, a handler for an entity collection, not entity instances. 
     264     * Invokes {@link #attachCollection(String, EntityFinder)} with the given 
     265     * {@link EntityFinder} and the URL "/{entityName}" where "{entityName}" is 
     266     * formed by calling {@link EntityHelper#getEntityName(Class)}. 
     267     *  
     268     * @param finder 
     269     *            The entity finder to attach. 
     270     * @return The finder for the entity. 
     271     * @throws IllegalStateException 
     272     *             If the finder has already been attached. 
     273     */ 
     274    public <E extends Object> EntityFinder<E> attachCollection( 
     275            EntityFinder<E> finder) { 
     276        return attachCollection("/" 
     277                + EntityHelper.getEntityName(finder.getEntityClass()), finder); 
     278    } 
     279 
     280    /** 
     281     * Attach an {@link EntityFinder} for handling {@link EntityCollection}s. 
     282     * That is, a handler for an entity collection, not entity instances. 
     283     * Invokes {@link #attachCollection(String, EntityFinder)} with a new 
     284     * {@link EntityFinder}. 
     285     *  
     286     * @param uriPattern 
     287     *            The URL pattern to attach the {@link EntityFinder} at. 
     288     * @param entityClass 
     289     *            The entity class to attach. 
     290     * @return The finder for the entity. 
     291     */ 
     292    public <E extends Object> EntityFinder<E> attachCollection( 
     293            String uriPattern, Class<E> entityClass) { 
     294        return attachCollection(uriPattern, new EntityFinder<E>(this, 
     295                entityClass, EntityCollection.class)); 
     296    } 
     297 
     298    /** 
     299     * Attach an {@link EntityFinder} for handling {@link EntityCollection}s. 
     300     * That is, a handler for an entity collection, not entity instances. 
     301     *  
     302     * @param uriPattern 
     303     *            The URL pattern to attach the {@link EntityFinder} at. 
     304     * @param finder 
     305     *            The entity finder to attach. 
     306     * @return The finder for the entity. 
     307     * @throws IllegalStateException 
     308     *             If the finder has already been attached. 
     309     */ 
     310    public <E extends Object> EntityFinder<E> attachCollection( 
     311            String uriPattern, EntityFinder<E> finder) { 
    132312        Route route = router.attach(uriPattern, finder); 
     313        finder.setRoute(route); 
     314        return finder; 
     315    } 
     316 
     317    /** 
     318     * Associate an {@link EntityFinder} with an extra URL. For 
     319     * {@link EntityResource} handling finders, the URL by default should 
     320     * contain "{id}" to define the entity id. 
     321     *  
     322     * @param uriPattern 
     323     *            The URL pattern to alias the {@link EntityFinder} to. 
     324     * @param finder 
     325     *            The entity finder to alias. 
     326     * @return The {@link Route} for the alias. 
     327     */ 
     328    public <E extends Object> Route alias(String uriPattern, 
     329            EntityFinder<E> finder) { 
     330        Route route = router.attach(uriPattern, finder); 
     331        finder.getAliases().add(route); 
    133332        return route; 
    134333    } 
    135334 
    136     public <E extends Object> E findEntity(Class<E> entityClass, String value) { 
     335    /** 
     336     * Locate an entity instance of the given class by converting the id string. 
     337     *  
     338     * @param entityClass 
     339     *            The entity class to locate. 
     340     * @param id 
     341     *            The entity id as a string. 
     342     * @return The entity instance matching the given id, or null if none was 
     343     *         found. 
     344     */ 
     345    public <E extends Object> E findEntity(Class<E> entityClass, String id) { 
    137346        EntityFinder finder = entities.get(entityClass); 
    138347        if (finder != null) { 
    139             Object id = finder.convertIdString(value); 
    140             if (id != null) { 
     348            Object idObj = finder.convertIdString(id); 
     349            if (idObj != null) { 
    141350                try { 
    142                     return getEntityManager().find(entityClass, id); 
     351                    return getEntityManager().find(entityClass, idObj); 
    143352                } catch (PersistenceException e) { 
    144353                    getLogger().log(Level.INFO, "Exception finding entity.", e); 
     
    149358    } 
    150359 
    151     private String createName(Class<? extends Object> model) { 
    152         String name = null; 
    153         if (model.isAnnotationPresent(Entity.class)) { 
    154             name = model.getSimpleName(); 
    155             Entity annotation = model.getAnnotation(Entity.class); 
    156             if (annotation.name() != null && !annotation.name().equals("")) { 
    157                 name = annotation.name(); 
    158             } 
    159         } 
    160         return name; 
    161     } 
    162  
    163360} 
  • trunk/src/main/java/org/sarugo/restlet/jpa/converter/ConverterHelper.java

    r3539 r3563  
    1 /** 
    2  * Copyright 2007 Sarugo Pty. Ltd.  
     1/* 
     2 * Copyright 2007, 2008 Sarugo Pty Ltd  
    33 *  
    44 * Licensed under the Common Development and Distribution License, 
     
    2828 * @author michael 
    2929 */ 
    30 public abstract class ConverterHelper { 
     30public class ConverterHelper { 
     31 
     32    private ConverterHelper() { 
     33    } 
    3134 
    3235    public static <T extends Object> T convertToType(Class<T> type, 
  • trunk/src/main/java/org/sarugo/restlet/jpa/converter/InputConverter.java

    r3539 r3563  
     1/* 
     2 * Copyright 2007, 2008 Sarugo Pty Ltd  
     3 *  
     4 * Licensed under the Common Development and Distribution License, 
     5 * you may not use this file except in compliance with the License. 
     6 * You may obtain a copy of the License at 
     7 *  
     8 *   http://www.sun.com/cddl/ 
     9 *    
     10 * Unless required by applicable law or agreed to in writing, software 
     11 * distributed under the License is distributed on an "AS IS" BASIS, 
     12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or  
     13 * implied. See the License for the specific language governing 
     14 * permissions and limitations under the License. 
     15 */ 
     16 
    117package org.sarugo.restlet.jpa.converter; 
    218 
    319import org.restlet.resource.Representation; 
    4 import org.sarugo.restlet.jpa.EntityResource; 
    520 
    621public interface InputConverter<E> { 
     
    924     * if unable to process the representation. 
    1025     */ 
    11     E acceptRepresentation(EntityResource<E> entityResource, 
    12             Representation representation); 
     26    E acceptRepresentation(Representation representation); 
    1327 
    1428    /** 
     
    1933     * @return true if updated 
    2034     */ 
    21     boolean storeRepresentation(EntityResource<E> entityResource, 
    22             Representation representation); 
     35    boolean storeRepresentation(E entity, Representation representation); 
     36 
    2337} 
  • trunk/src/main/java/org/sarugo/restlet/jpa/converter/OutputConverter.java

    r3539 r3563  
     1/* 
     2 * Copyright 2007, 2008 Sarugo Pty Ltd  
     3 *  
     4 * Licensed under the Common Development and Distribution License, 
     5 * you may not use this file except in compliance with the License. 
     6 * You may obtain a copy of the License at 
     7 *  
     8 *   http://www.sun.com/cddl/ 
     9 *    
     10 * Unless required by applicable law or agreed to in writing, software 
     11 * distributed under the License is distributed on an "AS IS" BASIS, 
     12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or  
     13 * implied. See the License for the specific language governing 
     14 * permissions and limitations under the License. 
     15 */ 
     16 
    117package org.sarugo.restlet.jpa.converter; 
    218 
     
    521import org.restlet.resource.Representation; 
    622import org.restlet.resource.Variant; 
     23import org.sarugo.restlet.jpa.EntityCollection; 
    724import org.sarugo.restlet.jpa.EntityResource; 
    825 
     
    1633     * Produce a representation for the provided entity. 
    1734     *  
    18      * @param entity 
     35     * @param entityResource 
    1936     *            the entity to represent. 
    2037     * @return 
    2138     */ 
    2239    Representation represent(EntityResource<E> entityResource, Variant variant); 
     40 
     41    /** 
     42     * Produce a representation for the provided entity collection. 
     43     *  
     44     * @param entityCollection 
     45     *            the entity collection to represent. 
     46     * @return 
     47     */ 
     48    Representation represent(EntityCollection<E> entityCollection, 
     49            Variant variant); 
    2350} 
  • trunk/src/main/java/org/sarugo/restlet/jpa/converter/form/FormEntityUpdateConverter.java

    r3539 r3563  
    1 package org.sarugo.restlet.jpa.converter; 
     1/* 
     2 * Copyright 2007, 2008 Sarugo Pty Ltd  
     3 *  
     4 * Licensed under the Common Development and Distribution License, 
     5 * you may not use this file except in compliance with the License. 
     6 * You may obtain a copy of the License at 
     7 *  
     8 *   http://www.sun.com/cddl/ 
     9 *    
     10 * Unless required by applicable law or agreed to in writing, software 
     11 * distributed under the License is distributed on an "AS IS" BASIS, 
     12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or  
     13 * implied. See the License for the specific language governing 
     14 * permissions and limitations under the License. 
     15 */ 
     16 
     17package org.sarugo.restlet.jpa.converter.form; 
    218 
    319import java.beans.IntrospectionException; 
     
    1329import org.restlet.data.Form; 
    1430import org.restlet.data.MediaType; 
    15 import org.restlet.data.Status; 
    1631import org.restlet.resource.Representation; 
    17 import org.restlet.resource.StringRepresentation; 
    18 import org.sarugo.restlet.jpa.EntityResource; 
     32import org.sarugo.restlet.jpa.PersistenceRouter; 
     33import org.sarugo.restlet.jpa.converter.ConverterHelper; 
     34import org.sarugo.restlet.jpa.converter.InputConverter; 
    1935 
    20 public class FormEntityUpdateConverter extends ConverterHelper
     36public class FormEntityUpdateConverter<E> implements InputConverter<E>
    2137 
    22     @Override 
    23     public boolean updateEntity(Object entity, EntityResource resource) { 
    24         Representation representation = resource.getRequest().getEntity(); 
     38    private final PersistenceRouter router; 
     39 
     40    private final Class<E> entityClass; 
     41 
     42    public FormEntityUpdateConverter(PersistenceRouter router, 
     43            Class<E> entityClass) { 
     44        this.router = router; 
     45        this.entityClass = entityClass; 
     46    } 
     47 
     48    public E acceptRepresentation(Representation representation) { 
     49        E entity = null; 
     50        try { 
     51            entity = entityClass.newInstance(); 
     52            if (!storeRepresentation(entity, representation)) { 
     53                entity = null; 
     54            } 
     55        } catch (InstantiationException e) { 
     56            router.getLogger().log(Level.WARNING, 
     57                    "Unable to instantiate entity class.", e); 
     58        } catch (IllegalAccessException e) { 
     59            router.getLogger().log(Level.WARNING, 
     60                    "Unable to instantiate entity class.", e); 
     61        } 
     62        return entity; 
     63    } 
     64 
     65    public boolean storeRepresentation(E entity, Representation representation) { 
    2566        if (!MediaType.APPLICATION_WWW_FORM.equals(representation 
    2667                .getMediaType())) { 
    2768            return false; 
    2869        } 
    29         Form data = resource.getRequest().getEntityAsForm(); 
    30         updateEntityFromForm(entity, resource, data); 
    31         return true; 
     70        Form data = new Form(representation); 
     71        return updateEntityFromForm(entity, data); 
    3272    } 
    3373 
    34     protected void updateEntityFromForm(Object entity, 
    35             EntityResource resource, Form data) { 
     74    protected boolean updateEntityFromForm(E entity, Form data) { 
     75        boolean updated = true; 
    3676        try { 
    3777            for (PropertyDescriptor p : Introspector.getBeanInfo( 
     
    5393                                entity, 
    5494                                ConverterHelper.convertToType(p 
    55                                         .getPropertyType(), value, resource)); 
     95                                        .getPropertyType(), value, router)); 
    5696                    } 
    5797                } 
    5898            } 
    5999        } catch (IntrospectionException e) { 
    60             resource.getLogger().log(Level.WARNING, 
     100            router.getLogger().log(Level.WARNING, 
    61101                    "Unable to update entity from form.", e); 
    62             resource.getResponse().setStatus(Status.SERVER_ERROR_INTERNAL)
     102            updated = false
    63103        } catch (IllegalAccessException e) { 
    64             resource.getLogger().log(Level.WARNING, 
     104            router.getLogger().log(Level.WARNING, 
    65105                    "Unable to update entity from form.", e); 
    66             resource.getResponse().setStatus(Status.SERVER_ERROR_INTERNAL)
     106            updated = false
    67107        } catch (IllegalArgumentException e) { 
    68             resource.getLogger().log(Level.WARNING, 
     108            router.getLogger().log(Level.WARNING, 
    69109                    "Unable to update entity from form.", e); 
    70             resource.getResponse().setStatus(Status.SERVER_ERROR_INTERNAL)
     110            updated = false
    71111        } catch (InvocationTargetException e) { 
    72             resource.getLogger().log(Level.WARNING, 
     112            router.getLogger().log(Level.WARNING, 
    73113                    "Unable to update entity from form.", e); 
    74             resource.getResponse().setStatus(Status.SERVER_ERROR_INTERNAL)
     114            updated = false
    75115        } catch (ParseException e) { 
    76             resource.getLogger().log(Level.INFO, 
     116            router.getLogger().log(Level.INFO, 
    77117                    "Unable to update entity from form.", e); 
    78             resource.getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST); 
    79             resource.getResponse().setEntity( 
    80                     new StringRepresentation(e.toString())); 
     118            updated = false; 
    81119        } 
     120        return updated; 
    82121    } 
    83122 
  • trunk/src/main/java/org/sarugo/restlet/jpa/converter/json/JSONConverter.java

    r3539 r3563  
    1 /** 
    2  * Copyright 2007 Sarugo Pty. Ltd.  
     1/* 
     2 * Copyright 2007, 2008 Sarugo Pty Ltd  
    33 *  
    44 * Licensed under the Common Development and Distribution License, 
     
    1515 */ 
    1616 
    17 package org.sarugo.restlet.jpa.converter
     17package org.sarugo.restlet.jpa.converter.json
    1818 
    1919import java.beans.IntrospectionException; 
     
    2222import java.lang.reflect.InvocationTargetException; 
    2323import java.util.ArrayList; 
     24import java.util.Collection; 
     25import java.util.Collections; 
    2426import java.util.HashMap; 
    2527import java.util.List; 
     
    3133import org.restlet.resource.StringRepresentation; 
    3234import org.restlet.resource.Variant; 
     35import org.sarugo.restlet.jpa.EntityCollection; 
    3336import org.sarugo.restlet.jpa.EntityResource; 
     37import org.sarugo.restlet.jpa.converter.OutputConverter; 
    3438 
    3539import com.sdicons.json.mapper.JSONMapper; 
    3640import com.sdicons.json.mapper.MapperException; 
    3741 
    38 public class JSONConverter extends ConverterHelper
     42public class JSONConverter<E> implements OutputConverter<E>
    3943 
    40         @Override 
    41         public void initEntityVariants(EntityResource resource) { 
    42                 resource.getVariants().add(new Variant(MediaType.APPLICATION_JSON)); 
    43         } 
     44    private static final Collection<Variant> VARIANTS = Collections 
     45            .singleton(new Variant(MediaType.APPLICATION_JSON)); 
    4446 
    45         @Override 
    46         public Representation getEntityRepresentation(Variant variant, 
    47                         EntityResource resource) { 
    48                 if (MediaType.APPLICATION_JSON.equals(variant.getMediaType())) { 
    49                         try { 
    50                                 // Read each property from the entity and store in a map. 
    51                                 // For properties which point to other entities, convert 
    52                                 // to a URL and store that instead of the object. 
    53                                 Map<String, Object> entityValues = new HashMap<String, Object>(); 
    54                                 for (PropertyDescriptor p : Introspector.getBeanInfo( 
    55                                                 resource.getModel()).getPropertyDescriptors()) { 
    56                                         if (p.getWriteMethod() != null && p.getReadMethod() != null) { 
    57                                                 Object value = p.getReadMethod().invoke( 
    58                                                                 resource.getEntity()); 
    59                                                 if (resource.getRouter().getName(value.getClass()) != null) { 
    60                                                         // Convert "known" entities to URLs 
    61                                                         value = resource.getEntityReference(value) 
    62                                                                         .toString(false, false); 
    63                                                 } 
    64                                                 entityValues.put(p.getName(), value); 
    65                                         } 
    66                                 } 
    67                                 return new StringRepresentation(JSONMapper.toJSON(entityValues) 
    68                                                 .render(true), variant.getMediaType()); 
    69                         } catch (MapperException e) { 
    70                                 resource.getLogger().log(Level.WARNING, 
    71                                                 "Unable to map entity to JSON", e); 
    72                         } catch (IntrospectionException e) { 
    73                                 resource.getLogger().log(Level.WARNING, 
    74                                                 "Unable to map entity to JSON", e); 
    75                         } catch (IllegalArgumentException e) { 
    76                                 resource.getLogger().log(Level.WARNING, 
    77                                                 "Unable to map entity to JSON", e); 
    78                         } catch (IllegalAccessException e) { 
    79                                 resource.getLogger().log(Level.WARNING, 
    80                                                 "Unable to map entity to JSON", e); 
    81                         } catch (InvocationTargetException e) { 
    82                                 resource.getLogger().log(Level.WARNING, 
    83                                                 "Unable to map entity to JSON", e); 
    84                         } 
    85                 } 
    86                 return null; 
    87         } 
     47    public Collection<Variant> getVariants() { 
     48        return VARIANTS; 
     49    } 
    8850 
    89         @Override 
    90         public void initEntityListVariants(EntityResource resource) { 
    91                 resource.getVariants().add(new Variant(MediaType.APPLICATION_JSON)); 
    92         } 
     51    public Representation represent(EntityResource<E> entityResource, 
     52            Variant variant) { 
     53        if (MediaType.APPLICATION_JSON.equals(variant.getMediaType())) { 
     54            try { 
     55                // Read each property from the entity and store in a map. 
     56                // For properties which point to other entities, convert 
     57                // to a URL and store that instead of the object. 
     58                Map<String, Object> entityValues = new HashMap<String, Object>(); 
     59                for (PropertyDescriptor p : Introspector.getBeanInfo( 
     60                        entityResource.getFinder().getEntityClass()) 
     61                        .getPropertyDescriptors()) { 
     62                    if (p.getWriteMethod() != null && p.getReadMethod() != null) { 
     63                        Object value = p.getReadMethod().invoke( 
     64                                entityResource.getEntity()); 
     65                        String url = entityResource.getFinder().getRouter() 
     66                                .getEntityURL(value); 
     67                        if (url != null) { 
     68                            value = url; 
     69                        } 
     70                        entityValues.put(p.getName(), value); 
     71                    } 
     72                } 
     73                return new StringRepresentation(JSONMapper.toJSON(entityValues) 
     74                        .render(true), variant.getMediaType()); 
     75            } catch (MapperException e) { 
     76                entityResource.getLogger().log(Level.WARNING, 
     77                        "Unable to map entity to JSON", e); 
     78            } catch (IntrospectionException e) { 
     79                entityResource.getLogger().log(Level.WARNING, 
     80                        "Unable to map entity to JSON", e); 
     81            } catch (IllegalArgumentException e) { 
     82                entityResource.getLogger().log(Level.WARNING, 
     83                        "Unable to map entity to JSON", e); 
     84            } catch (IllegalAccessException e) { 
     85                entityResource.getLogger().log(Level.WARNING, 
     86                        "Unable to map entity to JSON", e); 
     87            } catch (InvocationTargetException e) { 
     88                entityResource.getLogger().log(Level.WARNING, 
     89                        "Unable to map entity to JSON", e); 
     90            } 
     91        } 
     92        return null; 
     93    } 
    9394 
    94         @Override 
    95         public Representation getEntityListRepresentation(Variant variant, 
    96                         EntityResource resource) { 
    97                 if (MediaType.APPLICATION_JSON.equals(variant.getMediaType())) { 
    98                         try { 
    99                                 List<String> urlList = new ArrayList<String>(resource 
    100                                                 .getEntities().size()); 
    101                                 for (Object entity : resource.getEntities()) { 
    102                                         urlList.add(resource.getEntityURI(entity)); 
    103                                 } 
    104                                 Map<String, Object> listObject = new HashMap<String, Object>(1, 1.0f); 
    105                                 listObject.put("entities", urlList); 
    106                                 return new StringRepresentation(JSONMapper.toJSON(listObject) 
    107                                                 .render(true), variant.getMediaType()); 
    108                         } catch (MapperException e) { 
    109                                 resource.getLogger().log(Level.WARNING, 
    110                                                 "Unable to map entity list to JSON", e); 
    111                         } catch (IllegalArgumentException e) { 
    112                                 resource.getLogger().log(Level.WARNING, 
    113                                                 "Unable to map entity list to JSON", e); 
    114                         } 
    115                 } 
    116                 return null; 
    117         } 
     95    public Representation represent(EntityCollection<E> entityCollection, 
     96            Variant variant) { 
     97        if (MediaType.APPLICATION_JSON.equals(variant.getMediaType())) { 
     98            try { 
     99                List<String> urlList = new ArrayList<String>(entityCollection 
     100                        .getEntityList().size()); 
     101                for (E entity : entityCollection.getEntityList()) { 
     102                    urlList.add(entityCollection.getFinder().getEntityURL( 
     103                            entity)); 
     104                } 
     105                Map<String, Object> listObject = new HashMap<String, Object>(1, 
     106                        1.0f); 
     107                listObject.put("entities", urlList); 
     108                return new StringRepresentation(JSONMapper.toJSON(listObject) 
     109                        .render(true), variant.getMediaType()); 
     110            } catch (MapperException e) { 
     111                entityCollection.getLogger().log(Level.WARNING, 
     112                        "Unable to map entity list to JSON", e); 
     113            } catch (IllegalArgumentException e) { 
     114                entityCollection.getLogger().log(Level.WARNING, 
     115                        "Unable to map entity list to JSON", e); 
     116            } 
     117        } 
     118        return null; 
     119    } 
    118120 
    119121} 
  • trunk/src/main/java/org/sarugo/restlet/jpa/converter/text/ReferenceListConverter.java

    r3539 r3563  
    1 /** 
    2  * Copyright 2007 Sarugo Pty. Ltd.  
     1/* 
     2 * Copyright 2007, 2008 Sarugo Pty Ltd  
    33 *  
    44 * Licensed under the Common Development and Distribution License, 
     
    1515 */ 
    1616 
    17 package org.sarugo.restlet.jpa.converter; 
     17package org.sarugo.restlet.jpa.converter.text; 
     18 
     19import java.util.ArrayList; 
     20import java.util.Collection; 
    1821 
    1922import org.restlet.data.MediaType; 
     
    2124import org.restlet.resource.Representation; 
    2225import org.restlet.resource.Variant; 
     26import org.sarugo.restlet.jpa.EntityCollection; 
    2327import org.sarugo.restlet.jpa.EntityResource; 
     28import org.sarugo.restlet.jpa.converter.OutputConverter; 
    2429 
    25 public class ReferenceListConverter extends ConverterHelper
     30public class ReferenceListConverter<E> implements OutputConverter<E>
    2631 
    27         @Override 
    28         public void initEntityListVariants(EntityResource resource) { 
    29                 resource.getVariants().add(new Variant(MediaType.TEXT_URI_LIST)); 
    30                 resource.getVariants().add(new Variant(MediaType.TEXT_HTML)); 
    31         } 
     32    private static final Collection<Variant> VARIANTS = new ArrayList<Variant>( 
     33            2); 
     34    static { 
     35        VARIANTS.add(new Variant(MediaType.TEXT_URI_LIST)); 
     36        VARIANTS.add(new Variant(MediaType.TEXT_HTML)); 
     37    } 
    3238 
    33         @Override 
    34         public Representation getEntityListRepresentation(Variant variant, 
    35                         EntityResource resource) { 
    36                 if (MediaType.TEXT_URI_LIST.equals(variant.getMediaType()) 
    37                                 || MediaType.TEXT_HTML.equals(variant.getMediaType())) { 
    38                         ReferenceList list = new ReferenceList(resource.getEntities() 
    39                                         .size()); 
    40                         list.setIdentifier(resource.getRequest().getResourceRef()); 
    41                         for (Object o : resource.getEntities()) { 
    42                                 list.add(resource.getEntityReference(o)); 
    43                         } 
    44                         if (MediaType.TEXT_URI_LIST.equals(variant.getMediaType())) { 
    45                                 return list.getTextRepresentation(); 
    46                         } else { 
    47                                 return list.getWebRepresentation(); 
    48                         } 
    49                 } 
    50                 return null; 
    51         } 
     39    public Collection<Variant> getVariants() { 
     40        return VARIANTS; 
     41    } 
     42 
     43    public Representation represent(EntityResource<E> entityResource, 
     44            Variant variant) { 
     45        return null; 
     46    } 
     47 
     48    public Representation represent(EntityCollection<E> entityCollection, 
     49            Variant variant) { 
     50        if (VARIANTS.contains(variant.getMediaType())) { 
     51            ReferenceList list = new ReferenceList(entityCollection 
     52                    .getEntityList().size()); 
     53            list.setIdentifier(entityCollection.getRequest().getResourceRef()); 
     54            for (E o : entityCollection.getEntityList()) { 
     55                list.add(entityCollection.getFinder().getEntityURL(o)); 
     56            } 
     57            if (MediaType.TEXT_URI_LIST.equals(variant.getMediaType())) { 
     58                return list.getTextRepresentation(); 
     59            } else { 
     60                return list.getWebRepresentation(); 
     61            } 
     62        } 
     63        return null; 
     64    } 
    5265 
    5366} 
  • trunk/src/main/java/org/sarugo/restlet/jpa/converter/text/StringEntityConverter.java

    r3539 r3563  
    1 /** 
    2  * Copyright 2007 Sarugo Pty. Ltd.  
     1/* 
     2 * Copyright 2007, 2008 Sarugo Pty Ltd  
    33 *  
    44 * Licensed under the Common Development and Distribution License, 
     
    1515 */ 
    1616 
    17 package org.sarugo.restlet.jpa.converter
     17package org.sarugo.restlet.jpa.converter.text
    1818 
    1919import java.util.Collection; 
     
    2424import org.restlet.resource.StringRepresentation; 
    2525import org.restlet.resource.Variant; 
     26import org.sarugo.restlet.jpa.EntityCollection; 
    2627import org.sarugo.restlet.jpa.EntityResource; 
     28import org.sarugo.restlet.jpa.converter.OutputConverter; 
    2729 
    2830public class StringEntityConverter<E> implements OutputConverter<E> { 
     
    4446    } 
    4547 
     48    public Representation represent(EntityCollection<E> entityCollection, 
     49            Variant variant) { 
     50        return null; 
     51    } 
     52 
    4653} 
  • trunk/src/test/java/org/sarugo/restlet/jpa/PersistenceResourceTests.java

    r3539 r3563  
    1717package org.sarugo.restlet.jpa; 
    1818 
    19 import java.util.ArrayList; 
    2019import java.util.logging.Level; 
    2120 
     
    3029import org.restlet.data.Request; 
    3130import org.restlet.data.Response; 
    32 import org.sarugo.restlet.jpa.converter.JSONConverter; 
    33 import org.sarugo.restlet.jpa.converter.StringEntityConverter; 
     31import org.sarugo.restlet.jpa.converter.json.JSONConverter; 
     32import org.sarugo.restlet.jpa.converter.text.StringEntityConverter; 
    3433 
    3534public class PersistenceResourceTests extends TestCase { 
    3635 
    37        @Entity(name = "foo") 
    38        public static class FooEntity { 
    39                @SuppressWarnings("unused") 
    40                @Id 
    41                private String id = "A"; 
     36    @Entity(name = "foo") 
     37    public static class FooEntity { 
     38        @SuppressWarnings("unused") 
     39        @Id 
     40        private String id = "A"; 
    4241 
    43                @SuppressWarnings("unused") 
    44                private String info = "I'm a foo."; 
     42        @SuppressWarnings("unused") 
     43        private String info = "I'm a foo."; 
    4544 
    46                @Override 
    47                public String toString() { 
    48                        return id + ":" + info; 
    49                
    50        
     45        @Override 
     46        public String toString() { 
     47            return id + ":" + info; 
     48       
     49   
    5150 
    52        @Entity(name = "bar") 
    53        public static class BarEntity { 
    54                @Id 
    55                private String id = "B"; 
     51    @Entity(name = "bar") 
     52    public static class BarEntity { 
     53        @Id 
     54        private String id = "B"; 
    5655 
    57                private String info = "I'm a bar."; 
     56        private String info = "I'm a bar."; 
    5857 
    59                private FooEntity foo = new FooEntity(); 
     58        private FooEntity foo = new FooEntity(); 
    6059 
    61                public FooEntity getFoo() { 
    62                        return foo; 
    63                
     60        public FooEntity getFoo() { 
     61            return foo; 
     62       
    6463 
    65                public void setFoo(FooEntity foo) { 
    66                        this.foo = foo; 
    67                
     64        public void setFoo(FooEntity foo) { 
     65            this.foo = foo; 
     66       
    6867 
    69                public String getId() { 
    70                        return id; 
    71                
     68        public String getId() { 
     69            return id; 
     70       
    7271 
    73                public void setId(String id) { 
    74                        this.id = id; 
    75                
     72        public void setId(String id) { 
     73            this.id = id; 
     74       
    7675 
    77                public String getInfo() { 
    78                        return info; 
    79                
     76        public String getInfo() { 
     77            return info; 
     78       
    8079 
    81                public void setInfo(String info) { 
    82                        this.info = info; 
    83                
     80        public void setInfo(String info) { 
     81            this.info = info; 
     82       
    8483 
    85        
     84   
    8685 
    87        private static class TestResource extends EntityResource
     86    private static class TestFinder<E> extends EntityFinder<E>
    8887 
    89                 public TestResource(PersistenceRouter router, Request request, 
    90                                 Response response, ResourceInfo ri) { 
    91                         super(router, request, response, ri); 
    92                 } 
     88        private final E testEntity; 
    9389 
    94                 @Override 
    95                 protected void initEntity() { 
    96                         String id = (String) getRequest().getAttributes().get("id"); 
    97                         if (id != null) { 
    98                                 try { 
    99                                         entity = getModel().newInstance(); 
    100                                 } catch (Exception e) { 
    101                                         throw new RuntimeException(e); 
    102                                 } 
    103                         } 
    104                 } 
     90        public TestFinder(PersistenceRouter router, Class<E> entityClass) 
     91                throws InstantiationException, IllegalAccessException { 
     92            super(router, entityClass, EntityResource.class); 
     93            testEntity = entityClass.newInstance(); 
     94        } 
    10595 
    106                 @Override 
    107                 protected void initEntityList() { 
    108                         entities = new ArrayList<Object>(1); 
    109                         try { 
    110                                 ((ArrayList<Object>) entities).add(getModel().newInstance()); 
    111                         } catch (Exception e) { 
    112                                 throw new RuntimeException(e); 
    113                         } 
    114                 } 
    115         } 
     96        @Override 
     97        public E getEntity(String id) { 
     98            return testEntity; 
     99        } 
     100    } 
    116101 
    117        private PersistenceRouter router; 
     102    private PersistenceRouter router; 
    118103 
    119         @Override 
    120         protected void setUp() throws Exception { 
    121                 super.setUp(); 
    122                 router = new PersistenceRouter(null, Persistence 
    123                                 .createEntityManagerFactory("test")); 
    124                 router.getLogger().setLevel(Level.OFF); 
    125                 router.attach(FooEntity.class).setResourceClass(TestResource.class) 
    126                                 .addConverter(new StringEntityConverter()); 
    127                 router.attach(BarEntity.class).setResourceClass(TestResource.class) 
    128                                 .addConverter(new JSONConverter()); 
    129         } 
     104    @Override 
     105    protected void setUp() throws Exception { 
     106        super.setUp(); 
     107        router = new PersistenceRouter(null, Persistence 
     108                .createEntityManagerFactory("test")); 
     109        router.getLogger().setLevel(Level.OFF); 
     110        router.attach(new TestFinder<FooEntity>(router, FooEntity.class)) 
     111                .getOutputConverters().add( 
     112                        new StringEntityConverter<FooEntity>()); 
     113        router.attach(new TestFinder<BarEntity>(router, BarEntity.class)) 
     114                .getOutputConverters().add(new JSONConverter<BarEntity>()); 
     115    } 
    130116 
    131         public void testEntityReferences() throws Exception { 
    132                 Request request = new Request(Method.GET, "http://localhost/foo/A"); 
    133                 EntityResource resource = new TestResource(router, request, null, 
    134                                 new ResourceInfo("foo", FooEntity.class)); 
    135                 assertEquals(".", resource.getEntityURI(new FooEntity())); 
    136                 assertEquals("http://localhost/foo/A", resource.getEntityReference( 
    137                                 new FooEntity()).toString()); 
    138                 assertEquals("../bar/B", resource.getEntityURI(new BarEntity())); 
    139                 assertEquals("http://localhost/bar/B", resource.getEntityReference( 
    140                                 new BarEntity()).toString()); 
    141         } 
     117    public void testEntityReferences() throws Exception { 
     118        assertEquals("/foo/A", router.getEntityURL(new FooEntity())); 
     119        assertEquals("/bar/B", router.getEntityURL(new BarEntity())); 
     120    } 
    142121 
    143        public void testEntityRepresentation() throws Exception { 
    144                Request request = new Request(Method.GET, "/foo/A"); 
    145                Response response = router.handle(request); 
    146                assertEquals("A:I'm a foo.", response.getEntity().getText()); 
    147        
     122    public void testEntityRepresentation() throws Exception { 
     123        Request request = new Request(Method.GET, "/foo/A"); 
     124        Response response = router.handle(request); 
     125        assertEquals("A:I'm a foo.", response.getEntity().getText()); 
     126   
    148127 
    149        public void testJSONEntityRepresentation() throws Exception { 
    150                Reference ref = new Reference("http://localhost/bar/B"); 
    151                ref.setBaseRef(new Reference("http://localhost")); 
    152                Request request = new Request(Method.GET, ref); 
    153                Response response = router.handle(request); 
    154                String expected = "{\n   \"foo\" : \"http://localhost/foo/A\",\n   \"info\" : \"I'm a bar.\",\n   \"id\" : \"B\"\n}"; 
    155                assertEquals(expected, response.getEntity().getText()); 
    156        
     128    public void testJSONEntityRepresentation() throws Exception { 
     129        Reference ref = new Reference("http://localhost/bar/B"); 
     130        ref.setBaseRef(new Reference("http://localhost")); 
     131        Request request = new Request(Method.GET, ref); 
     132        Response response = router.handle(request); 
     133        String expected = "{\n   \"foo\" : \"/foo/A\",\n   \"info\" : \"I'm a bar.\",\n   \"id\" : \"B\"\n}"; 
     134        assertEquals(expected, response.getEntity().getText()); 
     135   
    157136 
    158137} 
  • trunk/src/test/java/org/sarugo/restlet/jpa/PersistenceRouterTest.java

    r3539 r3563  
    66import org.restlet.Component; 
    77import org.restlet.data.Protocol; 
    8 import org.sarugo.restlet.jpa.converter.StringEntityConverter; 
     8import org.sarugo.restlet.jpa.converter.text.StringEntityConverter; 
    99 
    1010public class PersistenceRouterTest {