View Javadoc
1   /*
2    * Copyright 2010 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  package com.fatwire.gst.foundation.properties;
17  
18  import java.util.ArrayList;
19  import java.util.Arrays;
20  import java.util.Collection;
21  import java.util.HashSet;
22  
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  
26  import COM.FutureTense.Interfaces.ICS;
27  import COM.FutureTense.Interfaces.ISyncHash;
28  import COM.FutureTense.Util.ftErrors;
29  
30  import com.fatwire.assetapi.common.AssetAccessException;
31  import com.fatwire.assetapi.common.SiteAccessException;
32  import com.fatwire.assetapi.data.AssetData;
33  import com.fatwire.assetapi.data.AssetDataManager;
34  import com.fatwire.assetapi.data.AssetId;
35  import com.fatwire.assetapi.data.AttributeData;
36  import com.fatwire.assetapi.data.MutableAssetData;
37  import com.fatwire.assetapi.query.OpTypeEnum;
38  import com.fatwire.assetapi.query.Query;
39  import com.fatwire.assetapi.site.SiteInfo;
40  import com.fatwire.assetapi.site.SiteManager;
41  import com.fatwire.gst.foundation.CSRuntimeException;
42  import com.fatwire.gst.foundation.facade.assetapi.QueryBuilder;
43  import com.fatwire.gst.foundation.facade.assetapi.asset.TemplateAsset;
44  import com.fatwire.gst.foundation.facade.assetapi.asset.TemplateAssetAccess;
45  import com.fatwire.gst.foundation.facade.runtag.asset.AssetList;
46  import com.fatwire.gst.foundation.facade.runtag.render.LogDep;
47  import com.fatwire.system.SessionFactory;
48  import com.openmarket.xcelerate.asset.AssetIdImpl;
49  
50  /**
51   * Class representing properties stored as an asset. Can be basic or flex but
52   * fields are specifically defined
53   * 
54   * @author Tony Field
55   * @since 11-09-02
56   */
57  // TODO: Figure out how to assign these to a give site/publication
58  public final class AssetApiPropertyDao implements PropertyDao {
59      private static final Log LOG = LogFactory.getLog("com.fatwire.gst.foundation.properties");
60  
61      public static final String TYPE = "GSTProperty";
62      public static final String SUBTYPE = "GSTProperty";
63  
64      private static final int TIMEOUT_MINUTES = 60 * 24; // one day
65      private static final int MAX_SIZE = 1000000; // a million
66      private final ISyncHash _props;
67      private final ICS ics;
68      private final AssetDataManager assetDataManager;
69  
70      public static final PropertyDao getInstance(ICS ics) {
71          return newInstance(ics);
72      }
73  
74      public static final PropertyDao newInstance(ICS ics) {
75          if (ics == null) {
76              throw new IllegalArgumentException("ics must not be null.");
77          }
78  
79          return new AssetApiPropertyDao(ics);
80      }
81  
82      private AssetApiPropertyDao(ICS ics) {
83          this.ics = ics;
84          this.assetDataManager = (AssetDataManager)SessionFactory.getSession(ics).getManager(AssetDataManager.class.getName());
85          this._props = ics.GetSynchronizedHash(AssetApiPropertyDao.class.getName(), true, TIMEOUT_MINUTES, MAX_SIZE, true, true, Arrays.asList(ics.GetProperty("cs.dsn")+TYPE));
86      }
87  
88      public synchronized Property getProperty(String name) {
89          PropertyHolder ph = (PropertyHolder) _props.get(name);
90          if (ph == null) {
91              ph = _readProperty(name);
92              _props.put(name, ph);
93          }
94          if (ph.getId() != null) {
95              LogDep.logDep(ics, ph.getId());
96          }
97          return ph.getProp();
98      }
99  
100     @SuppressWarnings("unchecked")
101 	public synchronized Collection<String> getPropertyNames() {
102         return _props.keySet();
103     }
104 
105     private PropertyHolder _readProperty(String name) {
106         Query loadQuery = new QueryBuilder(TYPE, SUBTYPE).attributes("id", "name", "description", "value")
107                 .condition("status", OpTypeEnum.NOT_EQUALS, "VO")
108                 .condition("name", OpTypeEnum.EQUALS, name)
109                 .setBasicSearch(true)
110                 .setFixedList(true)  // we are being precise
111                 .toQuery();
112         TemplateAssetAccess templateAssetAccess = new TemplateAssetAccess(ics);
113         for (TemplateAsset d : templateAssetAccess.query(loadQuery)) {
114             if (LOG.isTraceEnabled())
115                 LOG.trace("Loaded property: " + name);
116             return new AssetApiPropertyDao.PropertyHolder(name, d.asString("description"), d.asString("value"), TYPE, d.asLong("id"));
117         }
118         if (LOG.isTraceEnabled())
119             LOG.trace("Property not found: "+name);
120         return AssetApiPropertyDao.PropertyHolder.EMPTY_HOLDER;
121     }
122 
123     /**
124      * Convenience method to set (or re-set) a property value
125      *
126      * @param name        property name
127      * @param description property description (optional)
128      * @param value       value as a string
129      */
130     public synchronized void setProperty(String name, String description, String value) {
131         if (name == null) throw new IllegalArgumentException("Cannot set a null property name");
132 
133         AssetId id = AssetList.lookupAssetId(ics, TYPE, name);
134         if (id == null) {
135             try {// add
136                 MutableAssetData data = assetDataManager.newAssetData("GSTProperty", "GSTProperty");
137                 data.getAttributeData("name").setData(name);
138                 data.getAttributeData("description").setData(description);
139                 data.getAttributeData("value").setData(value);
140                 _appendCurrentToPublist(data.getAttributeData("Publist"));
141                 assetDataManager.insert(Arrays.<AssetData>asList(data));
142                 id = data.getAssetId();
143             } catch (AssetAccessException e) {
144                 throw new CSRuntimeException("Could not add new property "+name, ftErrors.exceptionerr, e);
145             }
146         } else {
147             // replace
148             try {
149                 ArrayList<AssetData> sAssets = new ArrayList<AssetData>();
150                 for (MutableAssetData data : assetDataManager.readForUpdate(Arrays.asList(id))) {
151                     // sorry can't reset 'name'
152                     data.getAttributeData("description").setData(description);
153                     data.getAttributeData("value").setData(value);
154                     _appendCurrentToPublist(data.getAttributeData("Publist"));
155                     sAssets.add(data);
156                 }
157                 assetDataManager.update(sAssets); // there can only be one since we are loading by id
158             } catch (AssetAccessException e) {
159                 throw new CSRuntimeException("Could not update property "+name, ftErrors.exceptionerr, e);
160             }
161         }
162         // cache or re-cache
163         _props.put(name, new AssetApiPropertyDao.PropertyHolder(name, description, value, id.getType(), id.getId()));
164     }
165 
166     /**
167      * Set (or re-set) a property value
168      *
169      * @param property property object with name and value
170      */
171     public synchronized void setProperty(Property property) {
172         if (property == null) throw new IllegalArgumentException("Can't set a null property object");
173         setProperty(property.getName(), property.getDescription(), property.asString());
174     }
175 
176     @SuppressWarnings("unchecked")
177 	private void _appendCurrentToPublist(AttributeData data) {
178         String currentPub = _getCurrentSite();
179         if (currentPub != null) {
180             HashSet<String> pubs = new HashSet<String>();
181             pubs.add(currentPub);
182             pubs.addAll(data.getDataAsList());
183             data.setDataAsList(new ArrayList<String>(pubs));
184         }
185     }
186 
187     private String _getCurrentSite() {
188         String pubid = ics.GetSSVar("pubid");
189         if (pubid != null) {
190             long id = Long.valueOf(pubid);
191             SiteManager sm = (SiteManager) SessionFactory.getSession().getManager(SiteManager.class.getName());
192             try {
193                 for (SiteInfo si : sm.list()) {
194                     if (si.getId() == id) return si.getName();
195                 }
196             } catch (SiteAccessException e) {
197                 throw new CSRuntimeException("Could not determine name of current site: " + e, ftErrors.exceptionerr, e);
198             }
199         }
200         return null;
201     }
202 
203     @SuppressWarnings({ "unchecked", "rawtypes" })
204 	public synchronized void addToSite(String name, String ... site) {
205         if (name == null) throw new IllegalArgumentException("Invalid property name null");
206         AssetId id = AssetList.lookupAssetId(ics, "GSTProperty", name);
207         if (id == null) throw new IllegalArgumentException("Could not locate property "+id);
208 
209         try {
210             ArrayList<AssetData> sAssets = new ArrayList<AssetData>();
211             for (MutableAssetData data : assetDataManager.readForUpdate(Arrays.asList(id))) {
212                 HashSet<String> pubs = new HashSet<String>();
213                 pubs.addAll(Arrays.asList(site));
214                 AttributeData publistData = data.getAttributeData("Publist");
215                 pubs.addAll(publistData.getDataAsList());
216                 publistData.setDataAsList(new ArrayList(pubs));
217                 sAssets.add(data);
218             }
219             assetDataManager.update(sAssets);
220         } catch (AssetAccessException e) {
221             throw new CSRuntimeException("Failure adding property "+name+" to sites "+Arrays.asList(site), ftErrors.exceptionerr, e);
222         }
223     }
224 
225     private static class PropertyHolder {
226 
227         private static final PropertyHolder EMPTY_HOLDER = new PropertyHolder();
228         private final Property prop;
229         private final AssetId id;
230 
231         /**
232          * Default constructor for empty object.
233          */
234         private PropertyHolder() {
235             prop = null;
236             id = null;
237         }
238 
239         /**
240          * Deep copy constructor, to be used when adding, to prevent messy cache issues
241          * @param name
242          * @param description
243          * @param value
244          * @param type
245          * @param propid
246          */
247         private PropertyHolder (String name, String description, String value, String type, long propid) {
248             if (name == null) throw new IllegalArgumentException("Null name not allowed");
249             if (value == null) throw new IllegalArgumentException("Null value not allowed");
250             if (type == null) throw new IllegalArgumentException("Null property asset type not allowed");
251             this.prop = new PropertyImpl(name, description, value);
252             this.id = new AssetIdImpl(type, propid);
253         }
254 
255         private Property getProp() {
256             return prop;
257         }
258 
259         private AssetId getId() {
260             return id;
261         }
262     }
263 }