1    /*
2     * Copyright 2010 :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.component.util.admin.cleanup;
19   
20   import java.util.List;
21   import java.util.Locale;
22   
23   import org.hibernate.Session;
24   import org.hibernate.Transaction;
25   import org.hibernate.criterion.Restrictions;
26   import org.slf4j.Logger;
27   import org.slf4j.LoggerFactory;
28   import org.torweg.pulse.annotations.Action;
29   import org.torweg.pulse.annotations.RequestBean;
30   import org.torweg.pulse.annotations.RequestBean.Parameter;
31   import org.torweg.pulse.bundle.Controller;
32   import org.torweg.pulse.invocation.lifecycle.Lifecycle;
33   import org.torweg.pulse.service.PulseException;
34   import org.torweg.pulse.site.content.Content;
35   import org.torweg.pulse.site.content.ContentLocalizationMap;
36   import org.torweg.pulse.site.content.ContentNode;
37   import org.torweg.pulse.site.content.RegistryLocaleNode;
38   import org.torweg.pulse.site.map.Sitemap;
39   import org.torweg.pulse.util.LocaleUtils;
40   import org.torweg.pulse.util.entity.Node;
41   import org.torweg.pulse.util.requestbean.RequestAwareRequestBean;
42   
43   /**
44    * @author Thomas Weber
45    * @version $Revision$
46    */
47   public class CleanSitemapAndContentRegistry extends Controller {
48   
49       /**
50        * the logger for {@code CleanSitemapAndContentRegistry}.
51        */
52       private static final Logger LOGGER = LoggerFactory
53               .getLogger(CleanSitemapAndContentRegistry.class);
54   
55       /**
56        * cleans a given locale from the {@code Sitemap} and
57        * {@code ContentRegistry}.
58        * 
59        * @param requestBean
60        *            injected
61        */
62       @Action("cleanUpForLocale")
63       public final void cleanUpForLocale(@RequestBean final CleanUpBean requestBean) {
64           LOGGER.info("Starting to clean locale {}.", requestBean.getLocale());
65           cleanSitemapForLocale(requestBean.getLocale());
66           cleanContentRegistryForLocale(requestBean.getLocale());
67       }
68   
69       /**
70        * removes the {@code Sitemap} for the given locale.
71        * 
72        * @param locale
73        *            the locale
74        */
75       private void cleanSitemapForLocale(final Locale locale) {
76           Session s = Lifecycle.getHibernateDataSource().createNewSession();
77           Transaction tx = s.beginTransaction();
78           try {
79               Sitemap sitemap = (Sitemap) s.createCriteria(Sitemap.class)
80                       .add(Restrictions.eq("locale", locale)).uniqueResult();
81               if (sitemap != null) {
82                   s.delete(sitemap);
83               } else {
84                   LOGGER.warn("No sitemap found for locale {}", locale);
85               }
86               tx.commit();
87               if (sitemap != null) {
88                   LOGGER.info("Sitemap deleted for locale {}", locale);
89               }
90           } catch (Exception e) {
91               tx.rollback();
92               throw new PulseException("Error: " + e.getLocalizedMessage(), e);
93           } finally {
94               s.close();
95           }
96   
97       }
98   
99       /**
100       * cleans the {@code ContentRegistry} for the given locale.
101       * 
102       * @param locale
103       *            the locale
104       */
105      private void cleanContentRegistryForLocale(final Locale locale) {
106          LOGGER.info("Starting to clean ContentRegistry for locale {}", locale);
107          while (true) {
108              Session s = Lifecycle.getHibernateDataSource().createNewSession();
109              Transaction tx = s.beginTransaction();
110              try {
111                  @SuppressWarnings("unchecked")
112                  // type safety ensured by Hibernate
113                  List<RegistryLocaleNode> localeNodes = (List<RegistryLocaleNode>) s
114                          .createCriteria(RegistryLocaleNode.class)
115                          .add(Restrictions.eq("locale", locale))
116                          .add(Restrictions.isEmpty("childrenSet")).list();
117                  if (localeNodes.size() == 0) {
118                      LOGGER.info("No further locale nodes found. Stopping...");
119                      break;
120                  }
121                  tx.commit();
122                  int total = localeNodes.size();
123                  LOGGER.debug(
124                          "  > trying to delete {} nodes from the ContentRegistry for locale {}",
125                          total, locale);
126                  for (RegistryLocaleNode deleteNode : localeNodes) {
127                      tx = s.beginTransaction();
128                      if (deleteNode instanceof ContentNode) {
129                          // retrieve content that is to be deleted
130                          Content deleteContent = ((ContentNode) deleteNode)
131                                  .getContent();
132  
133                          // retrieve contents' localization-map
134                          ContentLocalizationMap locMap = deleteContent
135                                  .getLocalizationMap();
136  
137                          // remove content from localization map
138                          locMap.remove(deleteContent.getLocale());
139  
140                          // load deleteNodes' parent
141                          Node parent = deleteNode.getParent();
142  
143                          // delete
144                          parent.removeChild(deleteNode);
145  
146                          s.delete(deleteNode);
147                          s.delete(deleteContent);
148                          if (locMap.isEmpty()) {
149                              s.delete(locMap);
150                          } else {
151                              s.saveOrUpdate(locMap);
152                          }
153  
154                          // persist parent
155                          s.saveOrUpdate(parent);
156                      } else {
157                          // load deleteNodes' parent
158                          Node parent = deleteNode.getParent();
159  
160                          // delete
161                          parent.removeChild(deleteNode);
162                          s.delete(deleteNode);
163  
164                          // persist parent
165                          s.saveOrUpdate(parent);
166                      }
167  
168                      tx.commit();
169                  }
170              } catch (Exception e) {
171                  tx.rollback();
172                  throw new PulseException("Error: " + e.getLocalizedMessage(), e);
173              } finally {
174                  s.close();
175              }
176          }
177  
178      }
179  
180      /**
181       * request bean for clean up.
182       */
183      public static final class CleanUpBean extends RequestAwareRequestBean {
184  
185          /**
186           * the locale.
187           */
188          private Locale locale;
189  
190          /**
191           * injects the locale.
192           * 
193           * @param l
194           *            the locale
195           */
196          @Parameter("locale")
197          public void setLocale(final String l) {
198              this.locale = LocaleUtils.localeFromString(l);
199          }
200  
201          /**
202           * returns the locale.
203           * 
204           * @return the locale
205           */
206          public Locale getLocale() {
207              return this.locale;
208          }
209  
210      }
211  
212  }
213