PageRenderTime 53ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/projects/roller-5.0.1/weblogger-business/src/main/java/org/apache/roller/weblogger/business/jpa/JPAWeblogEntryManagerImpl.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 1421 lines | 995 code | 207 blank | 219 comment | 249 complexity | deb0a98cf786b995bfc2cbcac63931bc MD5 | raw file
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. The ASF licenses this file to You
  4. * under the Apache License, Version 2.0 (the "License"); you may not
  5. * 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. For additional information regarding
  15. * copyright in this work, please see the NOTICE file in the top level
  16. * directory of this distribution.
  17. */
  18. package org.apache.roller.weblogger.business.jpa;
  19. import java.util.ArrayList;
  20. import java.util.Calendar;
  21. import java.util.Collections;
  22. import java.util.Comparator;
  23. import java.util.Date;
  24. import java.util.Hashtable;
  25. import java.util.Iterator;
  26. import java.util.List;
  27. import java.util.Map;
  28. import java.text.SimpleDateFormat;
  29. import java.util.TreeMap;
  30. import java.sql.Timestamp;
  31. import javax.persistence.NoResultException;
  32. import javax.persistence.Query;
  33. import org.apache.commons.collections.comparators.ReverseComparator;
  34. import org.apache.commons.lang.StringUtils;
  35. import org.apache.commons.logging.Log;
  36. import org.apache.commons.logging.LogFactory;
  37. import org.apache.roller.weblogger.WebloggerException;
  38. import org.apache.roller.weblogger.business.Weblogger;
  39. import org.apache.roller.weblogger.pojos.WeblogEntryComment;
  40. import org.apache.roller.weblogger.pojos.WeblogHitCount;
  41. import org.apache.roller.weblogger.pojos.WeblogReferrer;
  42. import org.apache.roller.weblogger.pojos.StatCount;
  43. import org.apache.roller.weblogger.pojos.TagStat;
  44. import org.apache.roller.weblogger.pojos.TagStatComparator;
  45. import org.apache.roller.weblogger.pojos.TagStatCountComparator;
  46. import org.apache.roller.weblogger.pojos.WeblogCategory;
  47. import org.apache.roller.weblogger.pojos.WeblogEntry;
  48. import org.apache.roller.weblogger.pojos.WeblogEntryTagAggregate;
  49. import org.apache.roller.weblogger.pojos.WeblogEntryTag;
  50. import org.apache.roller.weblogger.pojos.Weblog;
  51. import org.apache.roller.weblogger.pojos.WeblogEntryAttribute;
  52. import org.apache.roller.weblogger.pojos.StatCountCountComparator;
  53. import org.apache.roller.weblogger.pojos.User;
  54. import org.apache.roller.util.DateUtil;
  55. import org.apache.roller.weblogger.business.WeblogEntryManager;
  56. /**
  57. * JPAWeblogManagerImpl.java
  58. *
  59. * Created on May 31, 2006, 4:08 PM
  60. *
  61. */
  62. @com.google.inject.Singleton
  63. public class JPAWeblogEntryManagerImpl implements WeblogEntryManager {
  64. protected static Log log = LogFactory.getLog(
  65. JPAWeblogEntryManagerImpl.class);
  66. private final Weblogger roller;
  67. private final JPAPersistenceStrategy strategy;
  68. // cached mapping of entryAnchors -> entryIds
  69. private Hashtable entryAnchorToIdMap = new Hashtable();
  70. /* inline creation of reverse comparator, anonymous inner class */
  71. private static final Comparator reverseComparator = new ReverseComparator();
  72. private static final Comparator tagStatNameComparator = new TagStatComparator();
  73. private static final Comparator tagStatCountReverseComparator =
  74. Collections.reverseOrder(TagStatCountComparator.getInstance());
  75. private static final Comparator statCountCountReverseComparator =
  76. Collections.reverseOrder(StatCountCountComparator.getInstance());
  77. @com.google.inject.Inject
  78. protected JPAWeblogEntryManagerImpl(Weblogger roller, JPAPersistenceStrategy strategy) {
  79. log.debug("Instantiating JPA Weblog Manager");
  80. this.roller = roller;
  81. this.strategy = strategy;
  82. }
  83. /**
  84. * @inheritDoc
  85. */
  86. public void saveWeblogCategory(WeblogCategory cat) throws WebloggerException {
  87. boolean exists = getWeblogCategory(cat.getId()) != null;
  88. if (!exists) {
  89. if (isDuplicateWeblogCategoryName(cat)) {
  90. throw new WebloggerException("Duplicate category name, cannot save category");
  91. }
  92. // Newly added object. If it has a parent,
  93. // maintain relationship from both sides
  94. WeblogCategory parent = cat.getParent();
  95. if(parent != null) {
  96. parent.getWeblogCategories().add(cat);
  97. }
  98. }
  99. // update weblog last modified date. date updated by saveWebsite()
  100. roller.getWeblogManager().saveWeblog(cat.getWebsite());
  101. this.strategy.store(cat);
  102. }
  103. /**
  104. * @inheritDoc
  105. */
  106. public void removeWeblogCategory(WeblogCategory cat)
  107. throws WebloggerException {
  108. if(cat.retrieveWeblogEntries(true).size() > 0) {
  109. throw new WebloggerException("Cannot remove category with entries");
  110. }
  111. // remove cat
  112. this.strategy.remove(cat);
  113. //relationship management for the other side
  114. WeblogCategory parent = cat.getParent();
  115. if(parent != null) {
  116. parent.getWeblogCategories().remove(cat);
  117. }
  118. // update website default cats if needed
  119. if(cat.getWebsite().getBloggerCategory().equals(cat)) {
  120. WeblogCategory rootCat = this.getRootWeblogCategory(cat.getWebsite());
  121. cat.getWebsite().setBloggerCategory(rootCat);
  122. this.strategy.store(cat.getWebsite());
  123. }
  124. if(cat.getWebsite().getDefaultCategory().equals(cat)) {
  125. WeblogCategory rootCat = this.getRootWeblogCategory(cat.getWebsite());
  126. cat.getWebsite().setDefaultCategory(rootCat);
  127. this.strategy.store(cat.getWebsite());
  128. }
  129. // update weblog last modified date. date updated by saveWebsite()
  130. roller.getWeblogManager().saveWeblog(
  131. cat.getWebsite());
  132. }
  133. /**
  134. * @inheritDoc
  135. */
  136. public void moveWeblogCategory(WeblogCategory srcCat, WeblogCategory destCat)
  137. throws WebloggerException {
  138. // TODO: this check should be made before calling this method?
  139. if (destCat.descendentOf(srcCat)) {
  140. throw new WebloggerException(
  141. "ERROR cannot move parent category into it's own child");
  142. }
  143. log.debug("Moving category "+srcCat.getPath() +
  144. " under "+destCat.getPath());
  145. WeblogCategory oldParent = srcCat.getParent();
  146. if(oldParent != null) {
  147. oldParent.getWeblogCategories().remove(srcCat);
  148. }
  149. srcCat.setParent(destCat);
  150. destCat.getWeblogCategories().add(srcCat);
  151. if("/".equals(destCat.getPath())) {
  152. srcCat.setPath("/"+srcCat.getName());
  153. } else {
  154. srcCat.setPath(destCat.getPath() + "/" + srcCat.getName());
  155. }
  156. saveWeblogCategory(srcCat);
  157. // the main work to be done for a category move is to update the
  158. // path attribute of the category and all descendent categories
  159. updatePathTree(srcCat);
  160. }
  161. // updates the paths of all descendents of the given category
  162. private void updatePathTree(WeblogCategory cat)
  163. throws WebloggerException {
  164. log.debug("Updating path tree for category "+cat.getPath());
  165. WeblogCategory childCat = null;
  166. Iterator childCats = cat.getWeblogCategories().iterator();
  167. while(childCats.hasNext()) {
  168. childCat = (WeblogCategory) childCats.next();
  169. log.debug("OLD child category path was "+childCat.getPath());
  170. // update path and save
  171. if("/".equals(cat.getPath())) {
  172. childCat.setPath("/" + childCat.getName());
  173. } else {
  174. childCat.setPath(cat.getPath() + "/" + childCat.getName());
  175. }
  176. saveWeblogCategory(childCat);
  177. log.debug("NEW child category path is "+ childCat.getPath());
  178. // then make recursive call to update this cats children
  179. updatePathTree(childCat);
  180. }
  181. }
  182. /**
  183. * @inheritDoc
  184. */
  185. public void moveWeblogCategoryContents(WeblogCategory srcCat,
  186. WeblogCategory destCat)
  187. throws WebloggerException {
  188. // TODO: this check should be made before calling this method?
  189. if (destCat.descendentOf(srcCat)) {
  190. throw new WebloggerException(
  191. "ERROR cannot move parent category into it's own child");
  192. }
  193. // get all entries in category and subcats
  194. List results = srcCat.retrieveWeblogEntries(true);
  195. // Loop through entries in src cat, assign them to dest cat
  196. Iterator iter = results.iterator();
  197. Weblog website = destCat.getWebsite();
  198. while (iter.hasNext()) {
  199. WeblogEntry entry = (WeblogEntry) iter.next();
  200. entry.setCategory(destCat);
  201. entry.setWebsite(website);
  202. this.strategy.store(entry);
  203. }
  204. // Make sure website's default and bloggerapi categories
  205. // are valid after the move
  206. if (srcCat.getWebsite().getDefaultCategory().getId()
  207. .equals(srcCat.getId())
  208. || srcCat.getWebsite().getDefaultCategory().descendentOf(srcCat)) {
  209. srcCat.getWebsite().setDefaultCategory(destCat);
  210. this.strategy.store(srcCat.getWebsite());
  211. }
  212. if (srcCat.getWebsite().getBloggerCategory().getId()
  213. .equals(srcCat.getId())
  214. || srcCat.getWebsite().getBloggerCategory().descendentOf(srcCat)) {
  215. srcCat.getWebsite().setBloggerCategory(destCat);
  216. this.strategy.store(srcCat.getWebsite());
  217. }
  218. }
  219. /**
  220. * @inheritDoc
  221. */
  222. public void saveComment(WeblogEntryComment comment) throws WebloggerException {
  223. this.strategy.store(comment);
  224. // update weblog last modified date. date updated by saveWebsite()
  225. roller.getWeblogManager().saveWeblog(comment.getWeblogEntry().getWebsite());
  226. }
  227. /**
  228. * @inheritDoc
  229. */
  230. public void removeComment(WeblogEntryComment comment) throws WebloggerException {
  231. this.strategy.remove(comment);
  232. // update weblog last modified date. date updated by saveWebsite()
  233. roller.getWeblogManager().saveWeblog(comment.getWeblogEntry().getWebsite());
  234. }
  235. /**
  236. * @inheritDoc
  237. */
  238. // TODO: perhaps the createAnchor() and queuePings() items should go outside this method?
  239. public void saveWeblogEntry(WeblogEntry entry) throws WebloggerException {
  240. if (entry.getCategory() == null) {
  241. // Entry is invalid without category, so use weblog client cat
  242. WeblogCategory cat = entry.getWebsite().getBloggerCategory();
  243. if (cat == null) {
  244. // Sill no category, so use first one found
  245. cat = (WeblogCategory)
  246. entry.getWebsite().getWeblogCategories().iterator().next();
  247. }
  248. entry.setCategory(cat);
  249. }
  250. // Entry is invalid without local. if missing use weblog default
  251. if (entry.getLocale() == null) {
  252. entry.setLocale(entry.getWebsite().getLocale());
  253. }
  254. if (entry.getAnchor() == null || entry.getAnchor().trim().equals("")) {
  255. entry.setAnchor(this.createAnchor(entry));
  256. }
  257. for(Iterator it = entry.getAddedTags().iterator(); it.hasNext();) {
  258. String name = (String) it.next();
  259. updateTagCount(name, entry.getWebsite(), 1);
  260. }
  261. for(Iterator it = entry.getRemovedTags().iterator(); it.hasNext();) {
  262. String name = (String) it.next();
  263. updateTagCount(name, entry.getWebsite(), -1);
  264. }
  265. // if the entry was published to future, set status as SCHEDULED
  266. // we only consider an entry future published if it is scheduled
  267. // more than 1 minute into the future
  268. if ("PUBLISHED".equals(entry.getStatus()) &&
  269. entry.getPubTime().after(new Date(System.currentTimeMillis() + 60000))) {
  270. entry.setStatus(WeblogEntry.SCHEDULED);
  271. }
  272. // Store value object (creates new or updates existing)
  273. entry.setUpdateTime(new Timestamp(new Date().getTime()));
  274. this.strategy.store(entry);
  275. // update weblog last modified date. date updated by saveWebsite()
  276. if(entry.isPublished()) {
  277. roller.getWeblogManager().saveWeblog(entry.getWebsite());
  278. }
  279. if(entry.isPublished()) {
  280. // Queue applicable pings for this update.
  281. roller.getAutopingManager().queueApplicableAutoPings(entry);
  282. }
  283. }
  284. /**
  285. * @inheritDoc
  286. */
  287. public void removeWeblogEntry(WeblogEntry entry) throws WebloggerException {
  288. Weblog weblog = entry.getWebsite();
  289. Query q = strategy.getNamedQuery("WeblogReferrer.getByWeblogEntry");
  290. q.setParameter(1, entry);
  291. List referers = q.getResultList();
  292. for (Iterator iter = referers.iterator(); iter.hasNext();) {
  293. WeblogReferrer referer = (WeblogReferrer) iter.next();
  294. this.strategy.remove(referer);
  295. }
  296. // remove comments
  297. List comments = getComments(
  298. null, // website
  299. entry,
  300. null, // search String
  301. null, // startDate
  302. null, // endDate
  303. null, // status
  304. true, // reverse chrono order (not that it matters)
  305. 0, // offset
  306. -1); // no limit
  307. Iterator commentsIT = comments.iterator();
  308. while (commentsIT.hasNext()) {
  309. this.strategy.remove((WeblogEntryComment) commentsIT.next());
  310. }
  311. // remove tags aggregates
  312. if (entry.getTags() != null) {
  313. for(Iterator it = entry.getTags().iterator(); it.hasNext(); ) {
  314. WeblogEntryTag tag = (WeblogEntryTag) it.next();
  315. updateTagCount(tag.getName(), entry.getWebsite(), -1);
  316. it.remove();
  317. this.strategy.remove(tag);
  318. }
  319. }
  320. // remove attributes
  321. if (entry.getEntryAttributes() != null) {
  322. for (Iterator it = entry.getEntryAttributes().iterator(); it.hasNext(); ) {
  323. WeblogEntryAttribute att = (WeblogEntryAttribute) it.next();
  324. it.remove();
  325. this.strategy.remove(att);
  326. }
  327. }
  328. // TODO: can we eliminate this unnecessary flush with OpenJPA 1.0
  329. this.strategy.flush();
  330. // remove entry
  331. this.strategy.remove(entry);
  332. // update weblog last modified date. date updated by saveWebsite()
  333. if (entry.isPublished()) {
  334. roller.getWeblogManager().saveWeblog(weblog);
  335. }
  336. // remove entry from cache mapping
  337. this.entryAnchorToIdMap.remove(entry.getWebsite().getHandle()+":"+entry.getAnchor());
  338. }
  339. public List getNextPrevEntries(WeblogEntry current, String catName,
  340. String locale, int maxEntries, boolean next)
  341. throws WebloggerException {
  342. if (current == null) {
  343. log.debug("WeblogEntry current cannot be null");
  344. return Collections.emptyList();
  345. }
  346. Query query = null;
  347. List results = null;
  348. WeblogCategory category = null;
  349. if (catName != null && !catName.trim().equals("/")) {
  350. category = getWeblogCategoryByPath(current.getWebsite(), null,
  351. catName);
  352. }
  353. List params = new ArrayList();
  354. int size = 0;
  355. StringBuffer queryString = new StringBuffer();
  356. StringBuffer whereClause = new StringBuffer();
  357. queryString.append("SELECT e FROM WeblogEntry e WHERE ");
  358. params.add(size++, current.getWebsite());
  359. whereClause.append("e.website = ?" + size);
  360. params.add(size++, WeblogEntry.PUBLISHED);
  361. whereClause.append(" AND e.status = ?" + size);
  362. if (next) {
  363. params.add(size++, current.getPubTime());
  364. whereClause.append(" AND e.pubTime > ?" + size);
  365. } else {
  366. params.add(size++, current.getPubTime());
  367. whereClause.append(" AND e.pubTime < ?" + size);
  368. }
  369. if (catName != null && !catName.trim().equals("/")) {
  370. category = getWeblogCategoryByPath(current.getWebsite(), catName);
  371. if (category != null) {
  372. params.add(size++, category);
  373. whereClause.append(" AND e.category = ?" + size);
  374. } else {
  375. throw new WebloggerException("Cannot find category: " + catName);
  376. }
  377. }
  378. if(locale != null) {
  379. params.add(size++, locale + '%');
  380. whereClause.append(" AND e.locale like ?" + size);
  381. }
  382. if (next) {
  383. whereClause.append(" ORDER BY e.pubTime ASC");
  384. } else {
  385. whereClause.append(" ORDER BY e.pubTime DESC");
  386. }
  387. query = strategy.getDynamicQuery(queryString.toString() + whereClause.toString());
  388. for (int i=0; i<params.size(); i++) {
  389. query.setParameter(i+1, params.get(i));
  390. }
  391. query.setMaxResults(maxEntries);
  392. return query.getResultList();
  393. }
  394. /**
  395. * @inheritDoc
  396. */
  397. public WeblogCategory getRootWeblogCategory(Weblog website)
  398. throws WebloggerException {
  399. if (website == null)
  400. throw new WebloggerException("website is null");
  401. Query q = strategy.getNamedQuery(
  402. "WeblogCategory.getByWebsite&ParentNull");
  403. q.setParameter(1, website);
  404. try {
  405. return (WeblogCategory)q.getSingleResult();
  406. } catch (NoResultException e) {
  407. return null;
  408. }
  409. }
  410. /**
  411. * @inheritDoc
  412. */
  413. public List getWeblogCategories(Weblog website, boolean includeRoot)
  414. throws WebloggerException {
  415. if (website == null)
  416. throw new WebloggerException("website is null");
  417. if (includeRoot) return getWeblogCategories(website);
  418. Query q = strategy.getNamedQuery(
  419. "WeblogCategory.getByWebsite&ParentNotNull");
  420. q.setParameter(1, website);
  421. return q.getResultList();
  422. }
  423. /**
  424. * @inheritDoc
  425. */
  426. public List getWeblogCategories(Weblog website)
  427. throws WebloggerException {
  428. if (website == null)
  429. throw new WebloggerException("website is null");
  430. Query q = strategy.getNamedQuery(
  431. "WeblogCategory.getByWebsite");
  432. q.setParameter(1, website);
  433. return q.getResultList();
  434. }
  435. /**
  436. * @inheritDoc
  437. */
  438. public List getWeblogEntries(
  439. Weblog website,
  440. User user,
  441. Date startDate,
  442. Date endDate,
  443. String catName,
  444. List tags,
  445. String status,
  446. String text,
  447. String sortby,
  448. String sortOrder,
  449. String locale,
  450. int offset,
  451. int length) throws WebloggerException {
  452. WeblogCategory cat = null;
  453. if (StringUtils.isNotEmpty(catName) && website != null) {
  454. cat = getWeblogCategoryByPath(website, catName);
  455. if (cat == null) catName = null;
  456. }
  457. if (catName != null && catName.trim().equals("/")) {
  458. catName = null;
  459. }
  460. List params = new ArrayList();
  461. int size = 0;
  462. StringBuffer queryString = new StringBuffer();
  463. //queryString.append("SELECT e FROM WeblogEntry e WHERE ");
  464. if (tags == null || tags.size()==0) {
  465. queryString.append("SELECT e FROM WeblogEntry e WHERE ");
  466. } else {
  467. queryString.append("SELECT e FROM WeblogEntry e JOIN e.tags t WHERE ");
  468. queryString.append("(");
  469. for(int i = 0; i < tags.size(); i++) {
  470. if (i != 0) queryString.append(" OR ");
  471. params.add(size++, tags.get(i));
  472. queryString.append(" t.name = ?").append(size);
  473. }
  474. queryString.append(") AND ");
  475. }
  476. if (website != null) {
  477. params.add(size++, website.getId());
  478. queryString.append("e.website.id = ?").append(size);
  479. } else {
  480. params.add(size++, Boolean.TRUE);
  481. queryString.append("e.website.enabled = ?").append(size);
  482. }
  483. /*if (tags != null && tags.size() > 0) {
  484. // A JOIN with WeblogEntryTag in parent quert will cause a DISTINCT in SELECT clause
  485. // WeblogEntry has a clob field and many databases do not link DISTINCT for CLOB fields
  486. // Hence as a workaround using corelated EXISTS query.
  487. queryString.append(" AND EXISTS (SELECT t FROM WeblogEntryTag t WHERE "
  488. + " t.weblogEntry = e AND t.name IN (");
  489. final String PARAM_SEPERATOR = ", ";
  490. for(int i = 0; i < tags.size(); i++) {
  491. params.add(size++, tags.get(i));
  492. queryString.append("?").append(size).append(PARAM_SEPERATOR);
  493. }
  494. // Remove the trailing PARAM_SEPERATOR
  495. queryString.delete(queryString.length() - PARAM_SEPERATOR.length(),
  496. queryString.length());
  497. // Close the brace FOR IN clause and EXIST clause
  498. queryString.append(" ) )");
  499. }*/
  500. if (user != null) {
  501. params.add(size++, user.getUserName());
  502. queryString.append(" AND e.creatorUserName = ?").append(size);
  503. }
  504. if (startDate != null) {
  505. Timestamp start = new Timestamp(startDate.getTime());
  506. params.add(size++, start);
  507. queryString.append(" AND e.pubTime >= ?").append(size);
  508. }
  509. if (endDate != null) {
  510. Timestamp end = new Timestamp(endDate.getTime());
  511. params.add(size++, end);
  512. queryString.append(" AND e.pubTime <= ?").append(size);
  513. }
  514. if (cat != null && website != null) {
  515. params.add(size++, cat.getId());
  516. queryString.append(" AND e.category.id = ?").append(size);
  517. }
  518. if (status != null) {
  519. params.add(size++, status);
  520. queryString.append(" AND e.status = ?").append(size);
  521. }
  522. if (locale != null) {
  523. params.add(size++, locale + '%');
  524. queryString.append(" AND e.locale like ?").append(size);
  525. }
  526. if (text != null) {
  527. params.add(size++, '%' + text + '%');
  528. queryString.append(" AND ( e.text LIKE ?").append(size);
  529. queryString.append(" OR e.summary LIKE ? ").append(size);
  530. queryString.append(" OR e.title LIKE ?").append(size);
  531. queryString.append(") ");
  532. }
  533. if (sortby != null && sortby.equals("updateTime")) {
  534. queryString.append(" ORDER BY e.updateTime ");
  535. } else {
  536. queryString.append(" ORDER BY e.pubTime ");
  537. }
  538. if (sortOrder != null && sortOrder.equals(ASCENDING)) {
  539. queryString.append("ASC ");
  540. } else {
  541. queryString.append("DESC ");
  542. }
  543. Query query = strategy.getDynamicQuery(queryString.toString());
  544. for (int i=0; i<params.size(); i++) {
  545. query.setParameter(i+1, params.get(i));
  546. }
  547. if (offset != 0) {
  548. query.setFirstResult(offset);
  549. }
  550. if (length != -1) {
  551. query.setMaxResults(length);
  552. }
  553. return query.getResultList();
  554. }
  555. /**
  556. * @inheritDoc
  557. */
  558. public List getWeblogEntriesPinnedToMain(Integer max)
  559. throws WebloggerException {
  560. Query query = strategy.getNamedQuery(
  561. "WeblogEntry.getByPinnedToMain&statusOrderByPubTimeDesc");
  562. query.setParameter(1, Boolean.TRUE);
  563. query.setParameter(2, WeblogEntry.PUBLISHED);
  564. if (max != null) {
  565. query.setMaxResults(max.intValue());
  566. }
  567. return query.getResultList();
  568. }
  569. public void removeWeblogEntryAttribute(String name, WeblogEntry entry)
  570. throws WebloggerException {
  571. // seems silly, why is this not done in WeblogEntry?
  572. for (Iterator it = entry.getEntryAttributes().iterator(); it.hasNext();) {
  573. WeblogEntryAttribute entryAttribute = (WeblogEntryAttribute) it.next();
  574. if (entryAttribute.getName().equals(name)) {
  575. //Remove it from database
  576. this.strategy.remove(entryAttribute);
  577. //Remove it from the collection
  578. it.remove();
  579. }
  580. }
  581. }
  582. public void removeWeblogEntryTag(String name, WeblogEntry entry)
  583. throws WebloggerException {
  584. // seems silly, why is this not done in WeblogEntry?
  585. for (Iterator it = entry.getTags().iterator(); it.hasNext();) {
  586. WeblogEntryTag tag = (WeblogEntryTag) it.next();
  587. if (tag.getName().equals(name)) {
  588. //Call back the entity to adjust its internal state
  589. entry.onRemoveTag(name);
  590. //Remove it from database
  591. this.strategy.remove(tag);
  592. //Remove it from the collection
  593. it.remove();
  594. }
  595. }
  596. }
  597. /**
  598. * @inheritDoc
  599. */
  600. public WeblogEntry getWeblogEntryByAnchor(Weblog website,
  601. String anchor) throws WebloggerException {
  602. if (website == null)
  603. throw new WebloggerException("Website is null");
  604. if (anchor == null)
  605. throw new WebloggerException("Anchor is null");
  606. // mapping key is combo of weblog + anchor
  607. String mappingKey = website.getHandle()+":"+anchor;
  608. // check cache first
  609. // NOTE: if we ever allow changing anchors then this needs updating
  610. if(this.entryAnchorToIdMap.containsKey(mappingKey)) {
  611. WeblogEntry entry = this.getWeblogEntry((String) this.entryAnchorToIdMap.get(mappingKey));
  612. if(entry != null) {
  613. log.debug("entryAnchorToIdMap CACHE HIT - "+mappingKey);
  614. return entry;
  615. } else {
  616. // mapping hit with lookup miss? mapping must be old, remove it
  617. this.entryAnchorToIdMap.remove(mappingKey);
  618. }
  619. }
  620. // cache failed, do lookup
  621. Query q = strategy.getNamedQuery(
  622. "WeblogEntry.getByWebsite&AnchorOrderByPubTimeDesc");
  623. q.setParameter(1, website);
  624. q.setParameter(2, anchor);
  625. WeblogEntry entry = null;
  626. try {
  627. entry = (WeblogEntry)q.getSingleResult();
  628. } catch (NoResultException e) {
  629. entry = null;
  630. }
  631. // add mapping to cache
  632. if(entry != null) {
  633. log.debug("entryAnchorToIdMap CACHE MISS - "+mappingKey);
  634. this.entryAnchorToIdMap.put(mappingKey, entry.getId());
  635. }
  636. return entry;
  637. }
  638. /**
  639. * @inheritDoc
  640. */
  641. // TODO: this method should be removed and it's functionality moved to getWeblogEntries()
  642. public List getWeblogEntries(WeblogCategory cat, boolean subcats)
  643. throws WebloggerException {
  644. List results = null;
  645. if (!subcats) {
  646. Query q = strategy.getNamedQuery(
  647. "WeblogEntry.getByStatus&Category");
  648. q.setParameter(1, WeblogEntry.PUBLISHED);
  649. q.setParameter(2, cat);
  650. results = q.getResultList();
  651. } else {
  652. Query q = strategy.getNamedQuery(
  653. "WeblogEntry.getByStatus&Category.pathLike&Website");
  654. q.setParameter(1, WeblogEntry.PUBLISHED);
  655. q.setParameter(2, cat.getPath() + '%');
  656. q.setParameter(3, cat.getWebsite());
  657. results = q.getResultList();
  658. }
  659. return results;
  660. }
  661. /**
  662. * @inheritDoc
  663. */
  664. public String createAnchor(WeblogEntry entry) throws WebloggerException {
  665. // Check for uniqueness of anchor
  666. String base = entry.createAnchorBase();
  667. String name = base;
  668. int count = 0;
  669. while (true) {
  670. if (count > 0) {
  671. name = base + count;
  672. }
  673. Query q = strategy.getNamedQuery(
  674. "WeblogEntry.getByWebsite&Anchor");
  675. q.setParameter(1, entry.getWebsite());
  676. q.setParameter(2, name);
  677. List results = q.getResultList();
  678. if (results.size() < 1) {
  679. break;
  680. } else {
  681. count++;
  682. }
  683. }
  684. return name;
  685. }
  686. /**
  687. * @inheritDoc
  688. */
  689. public boolean isDuplicateWeblogCategoryName(WeblogCategory cat)
  690. throws WebloggerException {
  691. // ensure that no sibling categories share the same name
  692. WeblogCategory parent = cat.getParent();
  693. if (null != parent) {
  694. return (getWeblogCategoryByPath(
  695. cat.getWebsite(), cat.getPath()) != null);
  696. }
  697. return false;
  698. }
  699. /**
  700. * @inheritDoc
  701. */
  702. public boolean isWeblogCategoryInUse(WeblogCategory cat)
  703. throws WebloggerException {
  704. Query q = strategy.getNamedQuery("WeblogEntry.getByCategory");
  705. q.setParameter(1, cat);
  706. int entryCount = q.getResultList().size();
  707. if (entryCount > 0) {
  708. return true;
  709. }
  710. Iterator cats = cat.getWeblogCategories().iterator();
  711. while (cats.hasNext()) {
  712. WeblogCategory childCat = (WeblogCategory)cats.next();
  713. if (childCat.isInUse()) {
  714. return true;
  715. }
  716. }
  717. if (cat.getWebsite().getBloggerCategory().equals(cat)) {
  718. return true;
  719. }
  720. if (cat.getWebsite().getDefaultCategory().equals(cat)) {
  721. return true;
  722. }
  723. return false;
  724. }
  725. /**
  726. * @inheritDoc
  727. */
  728. public List getComments(
  729. Weblog website,
  730. WeblogEntry entry,
  731. String searchString,
  732. Date startDate,
  733. Date endDate,
  734. String status,
  735. boolean reverseChrono,
  736. int offset,
  737. int length) throws WebloggerException {
  738. List params = new ArrayList();
  739. int size = 0;
  740. StringBuffer queryString = new StringBuffer();
  741. queryString.append("SELECT c FROM WeblogEntryComment c ");
  742. StringBuffer whereClause = new StringBuffer();
  743. if (entry != null) {
  744. params.add(size++, entry);
  745. whereClause.append("c.weblogEntry = ?").append(size);
  746. } else if (website != null) {
  747. params.add(size++, website);
  748. whereClause.append("c.weblogEntry.website = ?").append(size);
  749. }
  750. if (searchString != null) {
  751. params.add(size++, "%" + searchString + "%");
  752. appendConjuctionToWhereclause(whereClause, "(c.url LIKE ?")
  753. .append(size).append(" OR c.content LIKE ?").append(size).append(")");
  754. }
  755. if (startDate != null) {
  756. Timestamp start = new Timestamp(startDate.getTime());
  757. params.add(size++, start);
  758. appendConjuctionToWhereclause(whereClause, "c.postTime >= ?").append(size);
  759. }
  760. if (endDate != null) {
  761. Timestamp end = new Timestamp(endDate.getTime());
  762. params.add(size++, end);
  763. appendConjuctionToWhereclause(whereClause, "c.postTime <= ?").append(size);
  764. }
  765. if (status != null) {
  766. String comparisionOperator;
  767. if("ALL_IGNORE_SPAM".equals(status)) {
  768. // we want all comments, except spam
  769. // so that means where status != SPAM
  770. status = WeblogEntryComment.SPAM;
  771. comparisionOperator = " <> ";
  772. } else {
  773. comparisionOperator = " = ";
  774. }
  775. params.add(size++, status);
  776. appendConjuctionToWhereclause(whereClause, "c.status ")
  777. .append(comparisionOperator).append('?').append(size);
  778. }
  779. if(whereClause.length() != 0) {
  780. queryString.append(" WHERE ").append(whereClause);
  781. }
  782. if (reverseChrono) {
  783. queryString.append(" ORDER BY c.postTime DESC");
  784. } else {
  785. queryString.append(" ORDER BY c.postTime ASC");
  786. }
  787. Query query = strategy.getDynamicQuery(queryString.toString());
  788. if (offset != 0) {
  789. query.setFirstResult(offset);
  790. }
  791. if (length != -1) {
  792. query.setMaxResults(length);
  793. }
  794. for (int i=0; i<params.size(); i++) {
  795. query.setParameter(i+1, params.get(i));
  796. }
  797. return query.getResultList();
  798. }
  799. /**
  800. * @inheritDoc
  801. */
  802. public int removeMatchingComments(
  803. Weblog website,
  804. WeblogEntry entry,
  805. String searchString,
  806. Date startDate,
  807. Date endDate,
  808. String status) throws WebloggerException {
  809. // TODO dynamic bulk delete query: I'd MUCH rather use a bulk delete,
  810. // but MySQL says "General error, message from server: "You can't
  811. // specify target table 'roller_comment' for update in FROM clause"
  812. List comments = getComments(
  813. website, entry, searchString, startDate, endDate,
  814. status, true, 0, -1);
  815. int count = 0;
  816. for (Iterator it = comments.iterator(); it.hasNext();) {
  817. WeblogEntryComment comment = (WeblogEntryComment) it.next();
  818. removeComment(comment);
  819. count++;
  820. }
  821. return count;
  822. }
  823. /**
  824. * @inheritDoc
  825. */
  826. public WeblogCategory getWeblogCategory(String id)
  827. throws WebloggerException {
  828. return (WeblogCategory) this.strategy.load(
  829. WeblogCategory.class, id);
  830. }
  831. //--------------------------------------------- WeblogCategory Queries
  832. /**
  833. * @inheritDoc
  834. */
  835. public WeblogCategory getWeblogCategoryByPath(Weblog website,
  836. String categoryPath) throws WebloggerException {
  837. return getWeblogCategoryByPath(website, null, categoryPath);
  838. }
  839. /**
  840. * @inheritDoc
  841. */
  842. // TODO: ditch this method in favor of getWeblogCategoryByPath(weblog, path)
  843. public WeblogCategory getWeblogCategoryByPath(Weblog website,
  844. WeblogCategory category, String path) throws WebloggerException {
  845. if (path == null || path.trim().equals("/")) {
  846. return getRootWeblogCategory(website);
  847. } else {
  848. String catPath = path;
  849. // all cat paths must begin with a '/'
  850. if(!catPath.startsWith("/")) {
  851. catPath = "/"+catPath;
  852. }
  853. // now just do simple lookup by path
  854. Query q = strategy.getNamedQuery(
  855. "WeblogCategory.getByPath&Website");
  856. q.setParameter(1, catPath);
  857. q.setParameter(2, website);
  858. try {
  859. return (WeblogCategory)q.getSingleResult();
  860. } catch (NoResultException e) {
  861. return null;
  862. }
  863. }
  864. }
  865. /**
  866. * @inheritDoc
  867. */
  868. public WeblogEntryComment getComment(String id) throws WebloggerException {
  869. return (WeblogEntryComment) this.strategy.load(WeblogEntryComment.class, id);
  870. }
  871. /**
  872. * @inheritDoc
  873. */
  874. public WeblogEntry getWeblogEntry(String id) throws WebloggerException {
  875. return (WeblogEntry)strategy.load(WeblogEntry.class, id);
  876. }
  877. /**
  878. * @inheritDoc
  879. */
  880. public Map getWeblogEntryObjectMap(
  881. Weblog website,
  882. Date startDate,
  883. Date endDate,
  884. String catName,
  885. List tags,
  886. String status,
  887. String locale,
  888. int offset,
  889. int length) throws WebloggerException {
  890. return getWeblogEntryMap(
  891. website,
  892. startDate,
  893. endDate,
  894. catName,
  895. tags,
  896. status,
  897. false,
  898. locale,
  899. offset,
  900. length);
  901. }
  902. /**
  903. * @inheritDoc
  904. */
  905. public Map getWeblogEntryStringMap(
  906. Weblog website,
  907. Date startDate,
  908. Date endDate,
  909. String catName,
  910. List tags,
  911. String status,
  912. String locale,
  913. int offset,
  914. int length
  915. ) throws WebloggerException {
  916. return getWeblogEntryMap(
  917. website,
  918. startDate,
  919. endDate,
  920. catName,
  921. tags,
  922. status,
  923. true,
  924. locale,
  925. offset,
  926. length);
  927. }
  928. private Map getWeblogEntryMap(
  929. Weblog website,
  930. Date startDate,
  931. Date endDate,
  932. String catName,
  933. List tags,
  934. String status,
  935. boolean stringsOnly,
  936. String locale,
  937. int offset,
  938. int length) throws WebloggerException {
  939. TreeMap map = new TreeMap(reverseComparator);
  940. List entries = getWeblogEntries(
  941. website,
  942. null, // user
  943. startDate,
  944. endDate,
  945. catName,
  946. tags,
  947. status,
  948. null, // text
  949. null, // sortBy
  950. null, // sortOrder
  951. locale,
  952. offset,
  953. length);
  954. Calendar cal = Calendar.getInstance();
  955. if (website != null) {
  956. cal.setTimeZone(website.getTimeZoneInstance());
  957. }
  958. SimpleDateFormat formatter = DateUtil.get8charDateFormat();
  959. for (Iterator wbItr = entries.iterator(); wbItr.hasNext();) {
  960. WeblogEntry entry = (WeblogEntry) wbItr.next();
  961. Date sDate = DateUtil.getNoonOfDay(entry.getPubTime(), cal);
  962. if (stringsOnly) {
  963. if (map.get(sDate) == null)
  964. map.put(sDate, formatter.format(sDate));
  965. } else {
  966. List dayEntries = (List) map.get(sDate);
  967. if (dayEntries == null) {
  968. dayEntries = new ArrayList();
  969. map.put(sDate, dayEntries);
  970. }
  971. dayEntries.add(entry);
  972. }
  973. }
  974. return map;
  975. }
  976. /**
  977. * @inheritDoc
  978. */
  979. public List getMostCommentedWeblogEntries(Weblog website,
  980. Date startDate, Date endDate, int offset,
  981. int length) throws WebloggerException {
  982. Query query = null;
  983. List queryResults = null;
  984. if (endDate == null) endDate = new Date();
  985. if (website != null) {
  986. if (startDate != null) {
  987. Timestamp start = new Timestamp(startDate.getTime());
  988. Timestamp end = new Timestamp(endDate.getTime());
  989. query = strategy.getNamedQuery(
  990. "WeblogEntryComment.getMostCommentedWeblogEntryByWebsite&EndDate&StartDate");
  991. query.setParameter(1, website);
  992. query.setParameter(2, end);
  993. query.setParameter(3, start);
  994. } else {
  995. Timestamp end = new Timestamp(endDate.getTime());
  996. query = strategy.getNamedQuery(
  997. "WeblogEntryComment.getMostCommentedWeblogEntryByWebsite&EndDate");
  998. query.setParameter(1, website);
  999. query.setParameter(2, end);
  1000. }
  1001. } else {
  1002. if (startDate != null) {
  1003. Timestamp start = new Timestamp(startDate.getTime());
  1004. Timestamp end = new Timestamp(endDate.getTime());
  1005. query = strategy.getNamedQuery(
  1006. "WeblogEntryComment.getMostCommentedWeblogEntryByEndDate&StartDate");
  1007. query.setParameter(1, end);
  1008. query.setParameter(2, start);
  1009. } else {
  1010. Timestamp end = new Timestamp(endDate.getTime());
  1011. query = strategy.getNamedQuery(
  1012. "WeblogEntryComment.getMostCommentedWeblogEntryByEndDate");
  1013. query.setParameter(1, end);
  1014. }
  1015. }
  1016. if (offset != 0) {
  1017. query.setFirstResult(offset);
  1018. }
  1019. if (length != -1) {
  1020. query.setMaxResults(length);
  1021. }
  1022. queryResults = query.getResultList();
  1023. List results = new ArrayList();
  1024. for (Iterator iter = queryResults.iterator(); iter.hasNext();) {
  1025. Object[] row = (Object[]) iter.next();
  1026. StatCount sc = new StatCount(
  1027. (String)row[1], // weblog handle
  1028. (String)row[2], // entry anchor
  1029. (String)row[3], // entry title
  1030. "statCount.weblogEntryCommentCountType", // stat desc
  1031. ((Long)row[0]).longValue()); // count
  1032. sc.setWeblogHandle((String)row[1]);
  1033. results.add(sc);
  1034. }
  1035. // Original query ordered by desc count.
  1036. // JPA QL doesn't allow queries to be ordered by agregates; do it in memory
  1037. Collections.sort(results, statCountCountReverseComparator);
  1038. return results;
  1039. }
  1040. /**
  1041. * @inheritDoc
  1042. */
  1043. public WeblogEntry getNextEntry(WeblogEntry current,
  1044. String catName, String locale) throws WebloggerException {
  1045. WeblogEntry entry = null;
  1046. List entryList = getNextPrevEntries(current, catName, locale, 1, true);
  1047. if (entryList != null && entryList.size() > 0) {
  1048. entry = (WeblogEntry)entryList.get(0);
  1049. }
  1050. return entry;
  1051. }
  1052. /**
  1053. * @inheritDoc
  1054. */
  1055. public WeblogEntry getPreviousEntry(WeblogEntry current,
  1056. String catName, String locale) throws WebloggerException {
  1057. WeblogEntry entry = null;
  1058. List entryList = getNextPrevEntries(current, catName, locale, 1, false);
  1059. if (entryList != null && entryList.size() > 0) {
  1060. entry = (WeblogEntry)entryList.get(0);
  1061. }
  1062. return entry;
  1063. }
  1064. /**
  1065. * @inheritDoc
  1066. */
  1067. public void release() {}
  1068. /**
  1069. * @inheritDoc
  1070. */
  1071. public void applyCommentDefaultsToEntries(Weblog website)
  1072. throws WebloggerException {
  1073. if (log.isDebugEnabled()) {
  1074. log.debug("applyCommentDefaults");
  1075. }
  1076. // TODO: Non-standard JPA bulk update, using parameter values in set clause
  1077. Query q = strategy.getNamedUpdate(
  1078. "WeblogEntry.updateAllowComments&CommentDaysByWebsite");
  1079. q.setParameter(1, website.getDefaultAllowComments());
  1080. q.setParameter(2, new Integer(website.getDefaultCommentDays()));
  1081. q.setParameter(3, website);
  1082. q.executeUpdate();
  1083. }
  1084. /**
  1085. * @inheritDoc
  1086. */
  1087. public List getPopularTags(Weblog website, Date startDate, int offset, int limit)
  1088. throws WebloggerException {
  1089. Query query = null;
  1090. List queryResults = null;
  1091. if (website != null) {
  1092. if (startDate != null) {
  1093. Timestamp start = new Timestamp(startDate.getTime());
  1094. query = strategy.getNamedQuery(
  1095. "WeblogEntryTagAggregate.getPopularTagsByWebsite&StartDate");
  1096. query.setParameter(1, website);
  1097. query.setParameter(2, start);
  1098. } else {
  1099. query = strategy.getNamedQuery(
  1100. "WeblogEntryTagAggregate.getPopularTagsByWebsite");
  1101. query.setParameter(1, website);
  1102. }
  1103. } else {
  1104. if (startDate != null) {
  1105. Timestamp start = new Timestamp(startDate.getTime());
  1106. query = strategy.getNamedQuery(
  1107. "WeblogEntryTagAggregate.getPopularTagsByWebsiteNull&StartDate");
  1108. query.setParameter(1, start);
  1109. } else {
  1110. query = strategy.getNamedQuery(
  1111. "WeblogEntryTagAggregate.getPopularTagsByWebsiteNull");
  1112. }
  1113. }
  1114. if (offset != 0) {
  1115. query.setFirstResult(offset);
  1116. }
  1117. if (limit != -1) {
  1118. query.setMaxResults(limit);
  1119. }
  1120. queryResults = query.getResultList();
  1121. double min = Integer.MAX_VALUE;
  1122. double max = Integer.MIN_VALUE;
  1123. List results = new ArrayList(limit);
  1124. for (Iterator iter = queryResults.iterator(); iter.hasNext();) {
  1125. Object[] row = (Object[]) iter.next();
  1126. TagStat t = new TagStat();
  1127. t.setName((String) row[0]);
  1128. t.setCount(((Number) row[1]).intValue());
  1129. min = Math.min(min, t.getCount());
  1130. max = Math.max(max, t.getCount());
  1131. results.add(t);
  1132. }
  1133. min = Math.log(1+min);
  1134. max = Math.log(1+max);
  1135. double range = Math.max(.01, max - min) * 1.0001;
  1136. for (Iterator iter = results.iterator(); iter.hasNext(); ) {
  1137. TagStat t = (TagStat) iter.next();
  1138. t.setIntensity((int) (1 + Math.floor(5 * (Math.log(1+t.getCount()) - min) / range)));
  1139. }
  1140. // sort results by name, because query had to sort by total
  1141. Collections.sort(results, tagStatNameComparator);
  1142. return results;
  1143. }
  1144. /**
  1145. * @inheritDoc
  1146. */
  1147. public List getTags(Weblog website, String sortBy,
  1148. String startsWith, int offset, int limit) throws WebloggerException {
  1149. Query query = null;
  1150. List queryResults = null;
  1151. boolean sortByName = sortBy == null || !sortBy.equals("count");
  1152. List params = new ArrayList();
  1153. int size = 0;
  1154. StringBuffer queryString = new StringBuffer();
  1155. queryString.append("SELECT w.name, SUM(w.total) FROM WeblogEntryTagAggregate w WHERE ");
  1156. if (website != null) {
  1157. params.add(size++, website.getId());
  1158. queryString.append(" w.weblog.id = ?").append(size);
  1159. } else {
  1160. queryString.append(" w.weblog IS NULL");
  1161. }
  1162. if (startsWith != null && startsWith.length() > 0) {
  1163. params.add(size++, startsWith + '%');
  1164. queryString.append(" AND w.name LIKE ?" + size);
  1165. }
  1166. if (sortBy != null && sortBy.equals("count")) {
  1167. sortBy = "w.total DESC";
  1168. } else {
  1169. sortBy = "w.name";
  1170. }
  1171. queryString.append(" GROUP BY w.name, w.total ORDER BY " + sortBy);
  1172. query = strategy.getDynamicQuery(queryString.toString());
  1173. for (int i=0; i<params.size(); i++) {
  1174. query.setParameter(i+1, params.get(i));
  1175. }
  1176. if (offset != 0) {
  1177. query.setFirstResult(offset);
  1178. }
  1179. if (limit != -1) {
  1180. query.setMaxResults(limit);
  1181. }
  1182. queryResults = query.getResultList();
  1183. List results = new ArrayList();
  1184. for (Iterator iter = queryResults.iterator(); iter.hasNext();) {
  1185. Object[] row = (Object[]) iter.next();
  1186. TagStat ce = new TagStat();
  1187. ce.setName((String) row[0]);
  1188. // The JPA query retrieves SUM(w.total) always as long
  1189. ce.setCount(((Long) row[1]).intValue());
  1190. results.add(ce);
  1191. }
  1192. if (sortByName) {
  1193. Collections.sort(results, tagStatNameComparator);
  1194. } else {
  1195. Collections.sort(results, tagStatCountReverseComparator);
  1196. }
  1197. return results;
  1198. }
  1199. /**
  1200. * @inheritDoc
  1201. */
  1202. public boolean getTagComboExists(List tags, Weblog weblog) throws WebloggerException{
  1203. if(tags == null || tags.size() == 0) {
  1204. return false;
  1205. }
  1206. StringBuffer queryString = new StringBuffer();
  1207. queryString.append("SELECT DISTINCT w.name ");
  1208. queryString.append("FROM WeblogEntryTagAggregate w WHERE w.name IN (");
  1209. //?1) AND w.weblog = ?2");
  1210. //Append tags as parameter markers to avoid potential escaping issues
  1211. //The IN clause would be of form (?1, ?2, ?3, ..)
  1212. ArrayList params = new ArrayList(tags.size() + 1);
  1213. final String PARAM_SEPERATOR = ", ";