1    /*
2     * Copyright 2006 :torweg free software group
3     * 
4     * This program is free software: you can redistribute it and/or modify
5     * it under the terms of the GNU General Public License as published by
6     * the Free Software Foundation, either version 3 of the License, or
7     * (at your option) any later version.
8     * 
9     * This program is distributed in the hope that it will be useful,
10    * but WITHOUT ANY WARRANTY; without even the implied warranty of
11    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    * GNU General Public License for more details.
13    * 
14    * You should have received a copy of the GNU General Public License
15    * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16    *
17    */
18   package org.torweg.pulse.site;
19   
20   import java.util.Locale;
21   import java.util.Set;
22   
23   import javax.persistence.CascadeType;
24   import javax.persistence.Entity;
25   import javax.persistence.JoinColumn;
26   import javax.persistence.JoinTable;
27   import javax.persistence.ManyToOne;
28   import javax.persistence.OneToOne;
29   import javax.xml.bind.annotation.XmlAccessOrder;
30   import javax.xml.bind.annotation.XmlAccessType;
31   import javax.xml.bind.annotation.XmlAccessorOrder;
32   import javax.xml.bind.annotation.XmlAccessorType;
33   import javax.xml.bind.annotation.XmlElement;
34   import javax.xml.bind.annotation.XmlRootElement;
35   import javax.xml.bind.annotation.XmlTransient;
36   
37   import org.hibernate.LazyInitializationException;
38   import org.jdom.Element;
39   import org.slf4j.Logger;
40   import org.slf4j.LoggerFactory;
41   import org.torweg.pulse.bundle.JDOMable;
42   import org.torweg.pulse.service.request.Command;
43   import org.torweg.pulse.service.request.CommandBuilder;
44   import org.torweg.pulse.service.request.Parameter;
45   import org.torweg.pulse.site.content.AbstractBasicContent;
46   import org.torweg.pulse.site.content.Content;
47   import org.torweg.pulse.site.map.SitemapNode;
48   import org.torweg.pulse.util.INamed;
49   import org.torweg.pulse.util.entity.AbstractNamableEntity;
50   
51   /**
52    * is an abstract base class for {@code View}s.
53    * <p>
54    * A {@code View} is used to assign a specific presentation of a {@code Content}
55    * to a specific {@code SitemapNode} in the {@code Sitemap}.
56    * </p>
57    * 
58    * @author Thomas Weber, Daniel Dietz
59    * @version $Revision: 1499 $
60    * @see SitemapNode
61    * @see Content
62    */
63   @Entity
64   @XmlRootElement(name = "view")
65   @XmlAccessorOrder(XmlAccessOrder.UNDEFINED)
66   @XmlAccessorType(XmlAccessType.FIELD)
67   public final class View extends AbstractNamableEntity implements INamed,
68           JDOMable {
69   
70       /**
71        * serialVersionUID.
72        */
73       private static final long serialVersionUID = -9207753073189282112L;
74   
75       /**
76        * the logger.
77        */
78       private static final Logger LOGGER = LoggerFactory.getLogger(View.class);
79   
80       /**
81        * the {@code SitemapNode} the {@code View} is assigned to.
82        */
83       @OneToOne(mappedBy = "view", cascade = CascadeType.ALL)
84       @XmlTransient
85       // -> this.getSitemapNodeIdJAXB()
86       private SitemapNode sitemapNode = null;
87   
88       /**
89        * the {@code Content} of the {@code View}.
90        */
91       @ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE,
92               CascadeType.REFRESH })
93       @JoinTable(name = "View_Content", joinColumns = { @JoinColumn(name = "view_id") }, inverseJoinColumns = @JoinColumn(name = "content_id"))
94       @XmlTransient
95       // -> this.getContentIdJAXB()
96       private Content content;
97   
98       /**
99        * the command matcher.
100       */
101      @ManyToOne(cascade = CascadeType.ALL)
102      @XmlTransient
103      // getter JAXB-annotated
104      private CommandBuilder commandBuilder;
105  
106      /**
107       * constructs a new blank {@code View}.
108       */
109      public View() {
110          super();
111      }
112  
113      /**
114       * builds a new {@code View} with the given {@code Content}.
115       * 
116       * @param c
117       *            the {@code Content} to be set
118       */
119      public View(final Content c) {
120          super();
121          this.content = c;
122      }
123  
124      /**
125       * Sets the {@code SitemapNode}.
126       * 
127       * @param sn
128       *            the {@code SitemapNode} to set
129       */
130      public void setSitemapNode(final SitemapNode sn) {
131          this.sitemapNode = sn;
132      }
133  
134      /**
135       * Returns the {@code SitemapNode}.
136       * 
137       * @return the {@code SitemapNode}
138       */
139      public SitemapNode getSitemapNode() {
140          return this.sitemapNode;
141      }
142  
143      /**
144       * For JAXB only.
145       * 
146       * @return this.getSitemapNode().getId()
147       */
148      @XmlElement(name = "sitemapnode-id")
149      @SuppressWarnings("unused")
150      @Deprecated
151      private Long getSitemapNodeIdJAXB() {
152          try {
153              return getSitemapNode().getId();
154          } catch (LazyInitializationException e) {
155              LOGGER.debug("ignored: {}", e.getLocalizedMessage());
156              return null;
157          }
158      }
159  
160      /**
161       * @param c
162       *            The content to set.
163       */
164      public void setContent(final Content c) {
165          this.content = (Content) c;
166      }
167  
168      /**
169       * @return Returns the content.
170       */
171      public Content getContent() {
172          return this.content;
173      }
174  
175      /**
176       * For JAXB only.
177       * 
178       * @return this.getContent()
179       */
180      @XmlElement(name = "content")
181      @SuppressWarnings("unused")
182      @Deprecated
183      private Content getContentJAXB() {
184          try {
185              return getContent();
186          } catch (LazyInitializationException e) {
187              LOGGER.debug("ignored: {}", e.getLocalizedMessage());
188              return null;
189          }
190      }
191  
192      /**
193       * Builds a {@code Command} producing the desired {@code View} for the
194       * {@code Content}.
195       * 
196       * <p>
197       * Actually calls {@link CommandBuilder#mixIn(Command)} and sets the suffix
198       * ({@link Command#setSuffix(String)}), if the {@code Content} of this
199       * {@code View} is an instance of {@link AbstractBasicContent}.
200       * </p>
201       * 
202       * @param currentCommand
203       *            the current {@code Command} used as a template
204       * @return the {@code Command} producing the desired {@code View} for the
205       *         {@code Content}
206       */
207      public Command getCommand(final Command currentCommand) {
208          Command c = this.commandBuilder.mixIn(currentCommand.createCopy(false));
209          if (this.sitemapNode != null) {
210              c.setSitemapID(this.sitemapNode.getId());
211          }
212          // add correct suffices for AbstractBasicContents
213          if (content instanceof AbstractBasicContent) {
214              c.setSuffix(((AbstractBasicContent) this.content).getSuffix());
215          }
216          return c;
217      }
218  
219      /**
220       * sets a {@code CommandBuilder}, which describes all fields which need
221       * modification to create the right {@code Command} for
222       * {@link View#getCommand(Command)}.
223       * 
224       * @param builder
225       *            the {@code CommandBuilder}
226       */
227      public void setCommandBuilder(final CommandBuilder builder) {
228          this.commandBuilder = builder;
229      }
230  
231      /**
232       * @return a basic JDOM representation
233       * @see org.torweg.pulse.bundle.JDOMable#deserializeToJDOM()
234       */
235      public Element deserializeToJDOM() {
236          Element view = new Element("View").setAttribute("class",
237                  this.getClass().getCanonicalName()).setAttribute("id",
238                  getId().toString()).setAttribute("name", getName());
239          if (this.content != null) {
240              view.addContent(getContent().deserializeToJDOM());
241          }
242          if (this.commandBuilder != null) {
243              view.addContent(getCommandBuilder().deserializeToJDOM());
244          }
245  
246          return view;
247      }
248  
249      /**
250       * returns the {@code Parameter}s of the {@code CommandBuilder}.
251       * 
252       * @return the {@code Parameter}s of the {@code CommandBuilder}
253       */
254      public Set<Parameter> getParameters() {
255          return this.commandBuilder.getParameters();
256      }
257  
258      /**
259       * removes a {@code Parameter} from the {@code CommandBuilder}.
260       * 
261       * @param parameter
262       *            the {@code Parameter} to be removed
263       */
264      public void removeParameter(final Parameter parameter) {
265          this.commandBuilder.removeParameter(parameter);
266      }
267  
268      /**
269       * sets the {@code Parameter}s of the {@code CommandBuilder}.
270       * 
271       * @param newParameters
272       *            the new {@code Parameter}s for the {@code CommandBuilder}
273       */
274      public void setParameters(final Set<Parameter> newParameters) {
275          this.commandBuilder.setParameters(newParameters);
276  
277      }
278  
279      /**
280       * returns a copy of the {@code CommandBuilder} of the {@code View}.
281       * 
282       * @return the {@code CommandBuilder} of the {@code View}
283       */
284      public CommandBuilder getCommandBuilder() {
285          return this.commandBuilder.createCopy();
286      }
287  
288      /**
289       * For JAXB only.
290       * 
291       * @return this.getCommandBuilder()
292       */
293      @XmlElement(name = "command-builder")
294      @SuppressWarnings("unused")
295      @Deprecated
296      private CommandBuilder getCommandBuilderJAXB() {
297          try {
298              return getCommandBuilder();
299          } catch (LazyInitializationException e) {
300              LOGGER.debug("ignored: {}", e.getLocalizedMessage());
301              return null;
302          }
303      }
304  
305      /**
306       * returns a copy of the {@code View}.
307       * 
308       * @return a copy of the {@code View}
309       */
310      public View createCopy() {
311          View v = new View();
312          v.setContent(getContent());
313          v.setCommandBuilder(getCommandBuilder());
314          v.setName(getName());
315          return v;
316      }
317  
318      /**
319       * creates a copy of the {@code View} in the given locale.&nbsp;If the
320       * localization map of the content associated with the {@code View} contains
321       * an entry for the given locale, the copied view is assigned the matching
322       * localization.
323       * 
324       * @param l
325       *            the target locale
326       * @return a copy of the view with the target locale
327       */
328      public View createCopy(final Locale l) {
329          View v = new View();
330          if (getContent() != null) {
331              v.setContent(getContent().getLocalizationMap().get(l));
332          }
333          if ((v.getContent() != null) && (getCommandBuilder() != null)) {
334              CommandBuilder cb = getCommandBuilder();
335              cb.setLocale(l);
336              v.setCommandBuilder(cb);
337          }
338          v.setName(getName());
339          return v;
340      }
341  
342  }
343