View Javadoc
1   /*
2    * Copyright 2008 FatWire Corporation. All Rights Reserved.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "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.apache.org/licenses/LICENSE-2.0
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 implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package tools.gsf.facade.assetapi;
18  
19  import COM.FutureTense.Interfaces.ICS;
20  import COM.FutureTense.Interfaces.IList;
21  import com.fatwire.assetapi.common.AssetAccessException;
22  import com.fatwire.assetapi.common.SiteAccessException;
23  import com.fatwire.assetapi.data.AssetData;
24  import com.fatwire.assetapi.data.AssetDataManager;
25  import com.fatwire.assetapi.data.AssetId;
26  import com.fatwire.assetapi.query.ConditionFactory;
27  import com.fatwire.assetapi.query.OpTypeEnum;
28  import com.fatwire.assetapi.query.Query;
29  import com.fatwire.assetapi.query.SimpleQuery;
30  import com.fatwire.assetapi.site.Site;
31  import com.fatwire.assetapi.site.SiteInfo;
32  import com.fatwire.assetapi.site.SiteManager;
33  import com.fatwire.system.Session;
34  import com.fatwire.system.SessionFactory;
35  import com.openmarket.xcelerate.asset.AssetIdImpl;
36  import tools.gsf.facade.runtag.asset.AssetList;
37  
38  import java.util.Arrays;
39  import java.util.Collection;
40  import java.util.Collections;
41  import java.util.Iterator;
42  import java.util.LinkedList;
43  import java.util.List;
44  
45  /**
46   * This class is a one-stop-shop for all read-only access to AssetData. It acts
47   * as a helper class to facilitate {@link AssetDataManager} use in a simplified
48   * way in delivery ContentServer templates.
49   * <p>
50   * This class is inspired by springframework data access template classes like
51   * org.springframework.jdbc.core.JdbcTemplate.
52   * <p>
53   * This class is not thread safe and should not be shared between threads.
54   *
55   * @author Dolf.Dijkstra
56   * @since Nov 23, 2009
57   */
58  public class AssetAccessTemplate {
59  
60      private final Session session;
61      private AssetDataManager assetDataManager;
62  
63      /**
64       * @param session session object
65       */
66      public AssetAccessTemplate(final Session session) {
67          super();
68          if (session == null) {
69              throw new IllegalArgumentException("session cannot be null.");
70          }
71          this.session = session;
72      }
73  
74      /**
75       * Constructor that accepts ICS as an argument.
76       *
77       * @param ics Content Server context object
78       */
79      public AssetAccessTemplate(final ICS ics) {
80          if (ics == null) {
81              throw new IllegalArgumentException("ics cannot be null.");
82          }
83          session = SessionFactory.getSession(ics);
84      }
85  
86      /**
87       * Helper method to create an AssetId from c and cid as string values.
88       *
89       * @param c   current asset
90       * @param cid content id
91       * @return the assetId for c/cid.
92       */
93      public AssetId createAssetId(final String c, final String cid) {
94          return new AssetIdImpl(c, Long.parseLong(cid));
95      }
96  
97      /**
98       * Helper method to create an AssetId from c and cid as string values.
99       *
100      * @param c   current asset
101      * @param cid content id
102      * @return the assetId for c/cid.
103      */
104     public AssetId createAssetId(final String c, final long cid) {
105         return new AssetIdImpl(c, cid);
106     }
107 
108     /**
109      * Method to read an asset and use the AssetMapper to transform the
110      * AssetData into another object as specified by the AssetMapper.
111      *
112      * @param <T>    type specified from asset mapper
113      * @param id     asset id
114      * @param mapper asset mapper
115      * @return the Object created by the mapper.
116      */
117     public <T> T readAsset(final AssetId id, final AssetMapper<T> mapper) {
118         final AssetDataManager m = getAssetDataManager();
119 
120         T t = null;
121         try {
122             final Iterable<AssetData> assets = m.read(Arrays.asList(id));
123             for (final AssetData assetData : assets) {
124                 t = mapper.map(assetData);
125             }
126         } catch (final AssetAccessException e) {
127             throw new RuntimeAssetAccessException(e);
128         }
129         return t;
130     }
131 
132     /**
133      * Method to read an asset and use the AssetMapper to transform the
134      * AssetData into another object as specified by the AssetMapper interface..
135      *
136      * @param <T>    type specified from asset mapper
137      * @param c      the assetType
138      * @param cid    the asset id
139      * @param mapper asset mapper
140      * @return the object created by the mapper.
141      */
142     public <T> T readAsset(final String c, final String cid, final AssetMapper<T> mapper) {
143         return readAsset(this.createAssetId(c, cid), mapper);
144     }
145 
146     /**
147      * Method to read an asset and use the AssetMapper to transform the
148      * AssetData into another object as specified by the AssetMapper.
149      *
150      * @param <T>    type specified from asset mapper
151      * @param c      the assetType
152      * @param cid    the asset id
153      * @param mapper asset mapper
154      * @return the object created by the mapper.
155      */
156     public <T> T readAsset(final String c, final long cid, final AssetMapper<T> mapper) {
157         return readAsset(new AssetIdImpl(c, cid), mapper);
158     }
159 
160     /**
161      * Method to read an asset and use the AssetMapper to transform the
162      * AssetData into another object as specified by the AssetMapper. Only the
163      * list of lister attributes is retrieved from the asset.
164      *
165      * @param <T>        type specified from asset mapper
166      * @param id         asset id
167      * @param mapper     asset mapper
168      * @param attributes array of attribute names
169      * @return the object created by the mapper.
170      */
171     public <T> T readAsset(final AssetId id, final AssetMapper<T> mapper, final String... attributes) {
172         final AssetDataManager m = getAssetDataManager();
173 
174         T t = null;
175         try {
176             final AssetData asset = m.readAttributes(id, Arrays.asList(attributes));
177             t = mapper.map(asset);
178         } catch (final AssetAccessException e) {
179             throw new RuntimeAssetAccessException(e);
180         }
181         return t;
182     }
183 
184     /**
185      * Method to read an asset and provide the AssetClosure with the AssetData.
186      * Only the list of lister attributes is retrieved from the asset.
187      *
188      * @param id         asset id
189      * @param closure    asset closure
190      * @param attributes array of attribute names
191      */
192     public void readAsset(final AssetId id, final AssetClosure closure, final String... attributes) {
193         final AssetDataManager m = getAssetDataManager();
194 
195         try {
196             final AssetData asset = m.readAttributes(id, Arrays.asList(attributes));
197             if (asset != null) {
198                 if (!closure.work(asset)) {
199                     return;
200                 }
201             }
202         } catch (final AssetAccessException e) {
203             throw new RuntimeAssetAccessException(e);
204         }
205     }
206 
207     /**
208      * Method to read an asset and pass the results to the closure for further
209      * handling.
210      *
211      * @param id      the assetid to read
212      * @param closure the closure
213      */
214     public void readAsset(final AssetId id, final AssetClosure closure) {
215         final AssetDataManager m = getAssetDataManager();
216 
217         try {
218             final Iterable<AssetData> assets = m.read(Arrays.asList(id));
219             for (final AssetData assetData : assets) {
220                 if (!closure.work(assetData)) {
221                     return;
222                 }
223 
224             }
225         } catch (final AssetAccessException e) {
226             throw new RuntimeAssetAccessException(e);
227         }
228 
229     }
230 
231     /**
232      * Method to read an asset and pass the results to the closure for further
233      * handling.
234      *
235      * @param ids     a list of AssetIds
236      * @param closure the closure
237      */
238     public void readAsset(final List<AssetId> ids, final AssetClosure closure) {
239         final AssetDataManager m = getAssetDataManager();
240 
241         try {
242             final Iterable<AssetData> assets = m.read(ids);
243             for (final AssetData assetData : assets) {
244                 if (!closure.work(assetData)) {
245                     return;
246                 }
247 
248             }
249         } catch (final AssetAccessException e) {
250             throw new RuntimeAssetAccessException(e);
251         }
252 
253     }
254 
255     /**
256      * Method to read an asset and pass the results to the closure for further
257      * handling.
258      *
259      * @param ids        a list of AssetIds
260      * @param closure    the closure
261      * @param attributes array of attribute names
262      */
263     public void readAsset(final Iterable<AssetId> ids, final AssetClosure closure, final String... attributes) {
264         final AssetDataManager m = getAssetDataManager();
265 
266         try {
267             for (final AssetId id : ids) {
268                 final AssetData asset = m.readAttributes(id, Arrays.asList(attributes));
269                 if (asset != null) {
270                     if (!closure.work(asset)) {
271                         return;
272                     }
273                 }
274 
275             }
276         } catch (final AssetAccessException e) {
277             throw new RuntimeAssetAccessException(e);
278         }
279 
280     }
281 
282     /**
283      * Reads an asset based on the listed attribute names
284      * <p>
285      * TODO: do we need to load the attribute values and prevent access to
286      * non-listed attributes (prevent lazy loading)
287      *
288      * @param id         the assetid
289      * @param attributes the list of attributes to return
290      * @return the asset found
291      */
292     public AssetData readAsset(final AssetId id, final String... attributes) {
293         final AssetDataManager m = getAssetDataManager();
294 
295         Iterable<AssetData> assets;
296         try {
297             assets = m.read(Arrays.asList(id));
298         } catch (final AssetAccessException e) {
299             throw new RuntimeAssetAccessException(e);
300         }
301         if (assets == null) {
302             return null;
303         }
304         if (assets instanceof List<?>) {
305             final List<AssetData> x = (List<AssetData>) assets;
306             if (x.isEmpty()) {
307                 return null;
308             } else {
309                 return x.get(0);
310             }
311         }
312         final Iterator<AssetData> i = assets.iterator();
313         if (i.hasNext()) {
314             return i.next();
315         }
316         return null;
317     }
318 
319     /**
320      * @return the manager
321      */
322     protected AssetDataManager getAssetDataManager() {
323         if (assetDataManager == null) {
324             assetDataManager = (AssetDataManager) session.getManager(AssetDataManager.class.getName());
325         }
326         return assetDataManager;
327     }
328 
329     /**
330      * @param id the assetid to read
331      * @return the assetdata for this id
332      */
333     public AssetData readAsset(final AssetId id) {
334 
335         final AssetDataManager m = getAssetDataManager();
336 
337         Iterable<AssetData> assets;
338         try {
339             assets = m.read(Collections.singletonList(id));
340         } catch (final AssetAccessException e) {
341             throw new RuntimeAssetAccessException(e);
342         }
343         if (assets == null) {
344             return null;
345         }
346         if (assets instanceof List<?>) {
347             final List<AssetData> x = (List<AssetData>) assets;
348             if (x.isEmpty()) {
349                 return null;
350             } else {
351                 return x.get(0);
352             }
353         }
354         final Iterator<AssetData> i = assets.iterator();
355         if (i.hasNext()) {
356             return i.next();
357         }
358         return null;
359     }
360 
361     /**
362      * @param query query object
363      * @return iterable with AssetData from the query result.
364      */
365     public Iterable<AssetData> readAssets(final Query query) {
366         final AssetDataManager m = getAssetDataManager();
367 
368         Iterable<AssetData> assets;
369         try {
370             assets = m.read(query);
371         } catch (final AssetAccessException e) {
372             throw new RuntimeAssetAccessException(e);
373         }
374 
375         return assets;
376     }
377 
378     /**
379      * Invokes the work(asset) method on the provided Closure for assets
380      * returned by the Query.
381      *
382      * @param query   the query
383      * @param closure the closure
384      */
385     public void readAssets(final Query query, final AssetClosure closure) {
386         final AssetDataManager m = getAssetDataManager();
387 
388         try {
389             for (final AssetData asset : m.read(query)) {
390                 if (!closure.work(asset)) {
391                     return;
392                 }
393 
394             }
395         } catch (final AssetAccessException e) {
396             throw new RuntimeAssetAccessException(e);
397         }
398     }
399 
400     /**
401      * Reading assets with the Query and using the mapper to transform the
402      * AssetData into another object, as specified by T.
403      *
404      * @param <T>    type specified from asset mapper
405      * @param query  query object
406      * @param mapper asset mapper
407      * @return the objects created by the mapper.
408      */
409     public <T> Iterable<T> readAssets(final Query query, final AssetMapper<T> mapper) {
410 
411         final List<T> r = new LinkedList<T>();
412 
413         for (final AssetData data : readAssets(query)) {
414             r.add(mapper.map(data));
415         }
416 
417         return r;
418     }
419 
420     /**
421      * Finds the assetid by the name of the asset in a particular site. The
422      * asset can not be voided.
423      *
424      * @param ics       Content Server context object
425      * @param assetType the type of the asset.
426      * @param name      the name of the asset.
427      * @param siteid    the Site id.
428      * @return the assetid, null if asset is not found.
429      */
430     public AssetId findByName(final ICS ics, final String assetType, final String name, final long siteid) {
431         // TODO: name does not need to be unique, how do we handle this?
432         final AssetList tag = new AssetList();
433         tag.setType(assetType);
434         tag.setField("name", name);
435         tag.setExcludeVoided(true);
436         tag.setPubid(Long.toString(siteid));
437         tag.setList("name__");
438         tag.execute(ics);
439 
440         final IList list = ics.GetList("name__");
441         ics.RegisterList("name__", null);
442         if (list != null && list.hasData()) {
443             list.moveTo(1);
444             try {
445                 return new AssetIdImpl(assetType, Long.parseLong(list.getValue("id")));
446             } catch (final NoSuchFieldException e) {
447                 throw new RuntimeException(e);
448             }
449         } else {
450             return null;
451         }
452 
453     }
454 
455     /**
456      * Finds the assetid by the name of the asset. The asset can not be voided.
457      *
458      * @param ics       Content Server context object
459      * @param assetType the type of the asset.
460      * @param name      the name of the asset.
461      * @return the assetid, null if asset is not found.
462      */
463 
464     public AssetId findByName(final ICS ics, final String assetType, final String name) {
465         // TODO: name does not need to be unique, how do we handle this?
466         final AssetList x = new AssetList();
467         x.setType(assetType);
468         x.setField("name", name);
469         x.setExcludeVoided(true);
470         x.setList("name__");
471         x.execute(ics);
472 
473         final IList list = ics.GetList("name__");
474         ics.RegisterList("name__", null);
475         if (list != null && list.hasData()) {
476             list.moveTo(1);
477             try {
478                 return new AssetIdImpl(assetType, Long.parseLong(list.getValue("id")));
479             } catch (final NoSuchFieldException e) {
480                 throw new RuntimeException(e);
481             }
482         } else {
483             return null;
484         }
485 
486     }
487 
488     /**
489      * Creates a Query to retrieve the asset by it's name.
490      *
491      * @param assetType string value of asset type
492      * @param assetName string value of asset name
493      * @return the simple query
494      */
495     public SimpleQuery createNameQuery(final String assetType, final String assetName) {
496         final SimpleQuery q = new SimpleQuery(assetType, null, ConditionFactory.createCondition("name",
497                 OpTypeEnum.EQUALS, assetName), Arrays.asList("id"));
498         q.getProperties().setIsBasicSearch(true);
499         return q;
500     }
501 
502     /**
503      * Finds the Site object by the given name.
504      *
505      * @param name the name of the site.
506      * @return the Site object.
507      */
508     public Site readSite(final String name) {
509         final SiteManager sm = (SiteManager) session.getManager(SiteManager.class.getName());
510         try {
511 
512             final List<Site> list = sm.read(Arrays.asList(name));
513             if (list == null || list.isEmpty()) {
514                 return null;
515             }
516             return list.get(0);
517         } catch (final SiteAccessException e) {
518             throw new SiteAccessRuntimeException(e);
519         }
520     }
521 
522     /**
523      * @param name site name
524      * @return the site info object
525      */
526     public SiteInfo readSiteInfo(final String name) {
527         final SiteManager sm = (SiteManager) session.getManager(SiteManager.class.getName());
528         try {
529 
530             for (SiteInfo si : sm.list()) {
531                 if (si.getName().equals(name)) {
532                     return si;
533                 }
534             }
535         } catch (final SiteAccessException e) {
536             throw new SiteAccessRuntimeException(e);
537         }
538         throw new SiteAccessRuntimeException("Site " + name + " does not exist in Content Server.");
539     }
540 
541     /**
542      * Reads the associated assets of the asset and returns the AssetIds.
543      *
544      * @param id              asset id
545      * @param associationType association type
546      * @return the assets from the associations.
547      */
548     public Collection<AssetId> readAssociatedAssetIds(final AssetId id, final String associationType) {
549         final List<AssetId> list = readAsset(id).getAssociatedAssets(associationType);
550         if (list == null) {
551             return Collections.emptyList();
552         }
553         return list;
554 
555     }
556 
557     /**
558      * Reads the associated assets of an asset and returns them as a
559      * ScatteredAsset. This takes care of the asset read operation of the
560      * associated assets. The returned ScatteredAssets are only loaded with the
561      * mentioned attributes.
562      *
563      * @param id              the parent asset
564      * @param associationType the name of the association or '-' for an unnamed
565      *                        association
566      * @param closure         the AssetClosure to work on.
567      * @param attributes      the list of attributes to load
568      */
569     public void readAssociatedAssets(final AssetId id, final String associationType, final AssetClosure closure,
570                                      final String... attributes) {
571         final List<AssetId> list = this.readAsset(id).getAssociatedAssets(associationType);
572         if (list == null || list.isEmpty()) {
573             return;
574         }
575 
576         for (final AssetId child : list) {
577             readAsset(child, closure, attributes);
578         }
579 
580     }
581 
582     /**
583      * Queries for a list of objects as mapped by the AssetMapper.
584      * <p>
585      * Sample queries are:
586      * <ul>
587      * <li>name='foo'</li>
588      * <li>name = 'foo'</li>
589      * <li>name = foo</li>
590      * <li>name= 'foo bar'</li>
591      * <li>size=[1,2]</li>
592      * <li>size{10,250}</li>
593      * <li>name!='foo'</li>
594      * </ul>
595      *
596      * @param <T>        type specified by asset mapper
597      * @param assetType  asset type
598      * @param subType    sub-type
599      * @param query      string value of query
600      * @param mapper     asset mapper
601      * @param attributes array of attribute names
602      * @return a iterable of assets.
603      * @see AssetAccessTemplate#query(String, String, String, AssetMapper,
604      * String...)
605      */
606     public <T> Iterable<T> query(final String assetType, final String subType, final String query,
607                                  AssetMapper<T> mapper, final String... attributes) {
608         final Query q = new QueryBuilder(assetType, subType).condition(query).attributes(attributes).toQuery();
609         return this.readAssets(q, mapper);
610     }
611 
612     /**
613      * Queries for a list of objects as mapped by the AssetMapper.
614      * <p>
615      * Sample queries are:
616      * <ul>
617      * <li>name='foo'</li>
618      * <li>name = 'foo'</li>
619      * <li>name = foo</li>
620      * <li>name= 'foo bar'</li>
621      * <li>size=[1,2]</li>
622      * <li>size{10,250}</li>
623      * <li>name!='foo'</li>
624      * </ul>
625      *
626      * @param <T>       type specified by asset mapper
627      * @param assetType asset type
628      * @param subType   sub-type
629      * @param query     string value of query
630      * @param mapper    asset mapper
631      * @return a iterable of assets.
632      */
633     public <T> Iterable<T> query(final String assetType, final String subType, final String query, AssetMapper<T> mapper) {
634         final Query q = new QueryBuilder(assetType, subType).condition(query).setReadAll(true).toQuery();
635         return this.readAssets(q, mapper);
636     }
637 
638 }