1    /**
2     * 
3     */
4    package org.torweg.pulse.site.content;
5    
6    import java.util.HashMap;
7    import java.util.Locale;
8    import java.util.Map;
9    
10   import javax.persistence.CascadeType;
11   import javax.persistence.Entity;
12   import javax.persistence.OneToOne;
13   import javax.persistence.Table;
14   import javax.persistence.UniqueConstraint;
15   import javax.xml.bind.annotation.XmlAccessOrder;
16   import javax.xml.bind.annotation.XmlAccessType;
17   import javax.xml.bind.annotation.XmlAccessorOrder;
18   import javax.xml.bind.annotation.XmlAccessorType;
19   import javax.xml.bind.annotation.XmlElement;
20   import javax.xml.bind.annotation.XmlRootElement;
21   
22   import net.sf.json.JSONObject;
23   
24   import org.jdom.Element;
25   import org.torweg.pulse.accesscontrol.User;
26   import org.torweg.pulse.bundle.Bundle;
27   import org.torweg.pulse.service.PulseException;
28   import org.torweg.pulse.service.request.ServiceRequest;
29   
30   /**
31    * a {@code ContentNode} is an entry in the websites {@code ContentRegistry}
32    * which can hold {@code Content}.
33    * 
34    * @author Daniel Dietz
35    * @version $Revision: 2071 $
36    */
37   @Entity
38   @Table(uniqueConstraints = { @UniqueConstraint(columnNames = { "content_id" }) })
39   @XmlRootElement(name = "content-node")
40   @XmlAccessorOrder(XmlAccessOrder.UNDEFINED)
41   @XmlAccessorType(XmlAccessType.FIELD)
42   public class ContentNode extends RegistryLocaleNode {
43   
44       /**
45        * The serialVersionUID.
46        */
47       private static final long serialVersionUID = 3281073481524648171L;
48   
49       /**
50        * the content.
51        */
52       @OneToOne(cascade = CascadeType.ALL, optional = false)
53       @XmlElement(name = "content")
54       private Content content;
55   
56       /**
57        * private constructor for Hibernate<sup>TM</sup>.
58        */
59       @Deprecated
60       protected ContentNode() {
61           super();
62       }
63   
64       /**
65        * creates a new ContentNode with a given {@code AbstractBasicContent}.
66        * 
67        * @param c
68        *            the {@code Content}
69        */
70       @SuppressWarnings("deprecation")
71       public ContentNode(final Content c) {
72           super();
73           setName(c.getName());
74           setContent(c);
75           setLocale(c.getLocale());
76           setBundle(c.getBundle());
77       }
78   
79       /**
80        * creates a new StoreContentNode with a given {@code Content} for the given
81        * {@code Bundle}.
82        * 
83        * @param c
84        *            the {@code Content}
85        * @param bundle
86        *            the {@code Bundle}
87        */
88       @SuppressWarnings("deprecation")
89       public ContentNode(final Content c, final Bundle bundle) {
90           super();
91           setName(c.getName());
92           setLocale(c.getLocale());
93           setBundle(bundle);
94           setContent(c);
95       }
96   
97       /**
98        * @return Returns the content.
99        */
100      public final Content getContent() {
101          return this.content;
102      }
103  
104      /**
105       * @param v
106       *            The content to set.
107       */
108      public final void setContent(final Content v) {
109          if (v == null) {
110              throw new PulseException(
111                      "ContentNode.content must not be set to null.");
112          }
113          this.content = v;
114      }
115  
116      /**
117       * serializes the {@code StoreContentNode} to JDOM.
118       * 
119       * @param req
120       *            the current request
121       * @return an {@code Element} representing the {@code StoreContentNode}.
122       * @see org.torweg.pulse.site.content.AbstractRegistryNode#deserializeToJDOM()
123       */
124      @Override
125      public Element deserializeToJDOM(final ServiceRequest req) {
126          Element jdom = new Element(this.getClass().getSimpleName())
127                  .setAttribute("id", this.getId().toString()).setAttribute(
128                          "name", this.getContent().getName()).setAttribute(
129                          "type", "AbstractRegistryNode").setAttribute("bundle",
130                          this.getBundle().getName()).setAttribute("bundleId",
131                          this.getBundle().getId().toString()).setAttribute(
132                          "disabledActions", this.getDisabledActions())
133                  .setAttribute("hasChildren",
134                          Boolean.toString(this.hasChildren()));
135          if (this.getContent() != null) {
136              jdom.setAttribute("contentType", this.getContent().getClass()
137                      .getCanonicalName());
138              jdom
139                      .setAttribute("contentId", this.getContent().getId()
140                              .toString());
141          }
142          Element actions = new Element("actions");
143          if (req != null) {
144              for (Map.Entry<String, String> entry : getActionURLs(req)
145                      .entrySet()) {
146                  actions.addContent(new Element(entry.getKey()).setText(entry
147                          .getValue()));
148              }
149          }
150          jdom.addContent(actions);
151          return jdom;
152      }
153  
154      /**
155       * returns {@code CREATE:ENABLE_DELETECONTENT}.
156       * 
157       * @return {@code CREATE:ENABLE_DELETECONTENT}
158       */
159      @Override
160      public String getDisabledActions() {
161          return "CREATE:ENABLE_DELETECONTENT";
162      }
163  
164      /**
165       * returns the {@code delete} and {@code edit} action URLs.
166       * 
167       * @param req
168       *            the current request
169       * @return the {@code delete} and {@code edit} action URLs
170       */
171      @Override
172      public Map<String, String> getActionURLs(final ServiceRequest req) {
173          Map<String, String> actions = new HashMap<String, String>();
174          actions.put("delete", getBundle().getViewTypes(this.getContent())
175                  .getDeleteView().getCommand(req.getCommand().createCopy(false))
176                  .toCommandURL(req));
177          actions
178                  .put("nodeEditContent", getBundle().getViewTypes(
179                          this.getContent()).getEditView().getCommand(
180                          req.getCommand().createCopy(false).clearParameters())
181                          .addHttpParameter("contentId",
182                                  this.getContent().getId().toString())
183                          .toCommandURL(req));
184          actions
185                  .put("expandEdit", getBundle().getViewTypes(this.getContent())
186                          .getExpandEditView().getCommand(
187                                  req.getCommand().createCopy(false)
188                                          .clearParameters()).addHttpParameter(
189                                  "contentId",
190                                  this.getContent().getId().toString())
191                          .toCommandURL(req));
192          actions.put("move", getBundle().getViewTypes(this).getMoveView()
193                  .getCommand(req.getCommand().createCopy(false)).toCommandURL(
194                          req));
195  
196          return actions;
197      }
198  
199      /**
200       * /** returns a {@code JSONObject} representation of the {@code
201       * ContentNode}.
202       * 
203       * @return a {@code JSONObject} representation of the {@code ContentNode}
204       */
205      @Override
206      public JSONObject toJSON() {
207          JSONObject nodeObject = super.toJSON();
208          nodeObject.remove("expandable");
209          nodeObject.put("leaf", true);
210          nodeObject.put("contentId", getContent().getId().toString());
211          nodeObject.put("contentType", getContent().getClass()
212                  .getCanonicalName());
213          return nodeObject;
214      }
215  
216      /**
217       * creates a copy of this node and its content in the given locale.
218       * 
219       * @param targetLocale
220       *            the target locale
221       * @param user
222       *            the current {@code User}
223       * @return the copy of the node and its content
224       * @throws UnsupportedOperationException
225       *             if the content of the node does not support
226       *             {@link Content#createCopy(Locale, User)}
227       */
228      public ContentNode createCopy(final Locale targetLocale, final User user)
229              throws UnsupportedOperationException {
230          Content copiedContent = getContent().createCopy(targetLocale, user);
231          ContentNode copy = new ContentNode(copiedContent, getBundle());
232          copy.setLocale(targetLocale);
233          return copy;
234      }
235  }
236