| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. The ASF licenses this file to You |
| * under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. For additional information regarding |
| * copyright in this work, please see the NOTICE file in the top level |
| * directory of this distribution. |
| */ |
| |
| package org.apache.roller.weblogger.business.jpa; |
| |
| import java.util.*; |
| import java.text.SimpleDateFormat; |
| import java.sql.Timestamp; |
| import jakarta.persistence.NoResultException; |
| import jakarta.persistence.Query; |
| import jakarta.persistence.TypedQuery; |
| |
| import org.apache.commons.lang3.StringUtils; |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| import org.apache.roller.util.RollerConstants; |
| import org.apache.roller.weblogger.WebloggerException; |
| import org.apache.roller.weblogger.business.Weblogger; |
| import org.apache.roller.weblogger.pojos.CommentSearchCriteria; |
| import org.apache.roller.weblogger.pojos.WeblogEntryComment; |
| import org.apache.roller.weblogger.pojos.WeblogEntryComment.ApprovalStatus; |
| import org.apache.roller.weblogger.pojos.WeblogEntrySearchCriteria; |
| import org.apache.roller.weblogger.pojos.WeblogHitCount; |
| import org.apache.roller.weblogger.pojos.StatCount; |
| import org.apache.roller.weblogger.pojos.TagStat; |
| import org.apache.roller.weblogger.pojos.TagStatComparator; |
| import org.apache.roller.weblogger.pojos.TagStatCountComparator; |
| import org.apache.roller.weblogger.pojos.WeblogCategory; |
| import org.apache.roller.weblogger.pojos.WeblogEntry; |
| import org.apache.roller.weblogger.pojos.WeblogEntry.PubStatus; |
| import org.apache.roller.weblogger.pojos.WeblogEntryTagAggregate; |
| import org.apache.roller.weblogger.pojos.WeblogEntryTag; |
| import org.apache.roller.weblogger.pojos.Weblog; |
| import org.apache.roller.weblogger.pojos.WeblogEntryAttribute; |
| import org.apache.roller.weblogger.pojos.StatCountCountComparator; |
| import org.apache.roller.util.DateUtil; |
| import org.apache.roller.weblogger.business.WeblogEntryManager; |
| |
| |
| /** |
| * JPAWeblogManagerImpl.java |
| * |
| * Created on May 31, 2006, 4:08 PM |
| * |
| */ |
| @com.google.inject.Singleton |
| public class JPAWeblogEntryManagerImpl implements WeblogEntryManager { |
| |
| private static final Log LOG = LogFactory.getLog(JPAWeblogEntryManagerImpl.class); |
| |
| private final Weblogger roller; |
| private final JPAPersistenceStrategy strategy; |
| |
| // cached mapping of entryAnchors -> entryIds |
| private final Map<String, String> entryAnchorToIdMap = Collections.synchronizedMap(new HashMap<String, String>()); |
| |
| private static final Comparator<TagStat> TAG_STAT_NAME_COMPARATOR = new TagStatComparator(); |
| |
| private static final Comparator<TagStat> TAG_STAT_COUNT_REVERSE_COMPARATOR = |
| Collections.reverseOrder(TagStatCountComparator.getInstance()); |
| |
| private static final Comparator<StatCount> STAT_COUNT_COUNT_REVERSE_COMPARATOR = |
| Collections.reverseOrder(StatCountCountComparator.getInstance()); |
| |
| |
| @com.google.inject.Inject |
| protected JPAWeblogEntryManagerImpl(Weblogger roller, JPAPersistenceStrategy strategy) { |
| LOG.debug("Instantiating JPA Weblog Manager"); |
| this.roller = roller; |
| this.strategy = strategy; |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public void saveWeblogCategory(WeblogCategory cat) throws WebloggerException { |
| boolean exists = getWeblogCategory(cat.getId()) != null; |
| if (!exists && isDuplicateWeblogCategoryName(cat)) { |
| throw new WebloggerException("Duplicate category name, cannot save category"); |
| } |
| |
| // update weblog last modified date. date updated by saveWebsite() |
| roller.getWeblogManager().saveWeblog(cat.getWeblog()); |
| this.strategy.store(cat); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public void removeWeblogCategory(WeblogCategory cat) |
| throws WebloggerException { |
| if(!cat.retrieveWeblogEntries(false).isEmpty()) { |
| throw new WebloggerException("Cannot remove category with entries"); |
| } |
| |
| cat.getWeblog().getWeblogCategories().remove(cat); |
| |
| // remove cat |
| this.strategy.remove(cat); |
| |
| if(cat.equals(cat.getWeblog().getBloggerCategory())) { |
| cat.getWeblog().setBloggerCategory(null); |
| this.strategy.store(cat.getWeblog()); |
| } |
| |
| // update weblog last modified date. date updated by saveWebsite() |
| roller.getWeblogManager().saveWeblog(cat.getWeblog()); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public void moveWeblogCategoryContents(WeblogCategory srcCat, |
| WeblogCategory destCat) |
| throws WebloggerException { |
| |
| // get all entries in category and subcats |
| List<WeblogEntry> results = srcCat.retrieveWeblogEntries(false); |
| |
| // Loop through entries in src cat, assign them to dest cat |
| Weblog website = destCat.getWeblog(); |
| for (WeblogEntry entry : results) { |
| entry.setCategory(destCat); |
| entry.setWebsite(website); |
| this.strategy.store(entry); |
| } |
| |
| // Update Blogger API category if applicable |
| WeblogCategory bloggerCategory = srcCat.getWeblog().getBloggerCategory(); |
| if (bloggerCategory != null && bloggerCategory.getId().equals(srcCat.getId())) { |
| srcCat.getWeblog().setBloggerCategory(destCat); |
| this.strategy.store(srcCat.getWeblog()); |
| } |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public void saveComment(WeblogEntryComment comment) throws WebloggerException { |
| this.strategy.store(comment); |
| |
| // update weblog last modified date. date updated by saveWebsite() |
| roller.getWeblogManager().saveWeblog(comment.getWeblogEntry().getWebsite()); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public void removeComment(WeblogEntryComment comment) throws WebloggerException { |
| this.strategy.remove(comment); |
| |
| // update weblog last modified date. date updated by saveWebsite() |
| roller.getWeblogManager().saveWeblog(comment.getWeblogEntry().getWebsite()); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| // TODO: perhaps the createAnchor() and queuePings() items should go outside this method? |
| @Override |
| public void saveWeblogEntry(WeblogEntry entry) throws WebloggerException { |
| |
| if (entry.getCategory() == null) { |
| // Entry is invalid without category, so use weblog client cat |
| WeblogCategory cat = entry.getWebsite().getBloggerCategory(); |
| if (cat == null) { |
| // Still no category, so use first one found |
| cat = entry.getWebsite().getWeblogCategories().iterator().next(); |
| } |
| entry.setCategory(cat); |
| } |
| |
| // Entry is invalid without local. if missing use weblog default |
| if (entry.getLocale() == null) { |
| entry.setLocale(entry.getWebsite().getLocale()); |
| } |
| |
| if (entry.getAnchor() == null || entry.getAnchor().isBlank()) { |
| entry.setAnchor(this.createAnchor(entry)); |
| } |
| |
| if (entry.isPublished()) { |
| // tag aggregates are updated only when entry published in order for |
| // tag cloud counts to match published articles |
| if (entry.getRefreshAggregates()) { |
| // blog entry wasn't published before, so all tags need to be incremented |
| for (WeblogEntryTag tag : entry.getTags()) { |
| updateTagCount(tag.getName(), entry.getWebsite(), 1); |
| } |
| } else { |
| // only new tags need to be incremented |
| for (WeblogEntryTag tag : entry.getAddedTags()) { |
| updateTagCount(tag.getName(), entry.getWebsite(), 1); |
| } |
| } |
| } else { |
| if (entry.getRefreshAggregates()) { |
| // blog entry no longer published so need to reduce aggregate count |
| for (WeblogEntryTag tag : entry.getTags()) { |
| updateTagCount(tag.getName(), entry.getWebsite(), -1); |
| } |
| } |
| } |
| |
| for (WeblogEntryTag tag : entry.getRemovedTags()) { |
| removeWeblogEntryTag(tag); |
| } |
| |
| // if the entry was published to future, set status as SCHEDULED |
| // we only consider an entry future published if it is scheduled |
| // more than 1 minute into the future |
| if (PubStatus.PUBLISHED.equals(entry.getStatus()) && |
| entry.getPubTime().after(new Date(System.currentTimeMillis() + RollerConstants.MIN_IN_MS))) { |
| entry.setStatus(PubStatus.SCHEDULED); |
| } |
| |
| // Store value object (creates new or updates existing) |
| entry.setUpdateTime(new Timestamp(new Date().getTime())); |
| |
| this.strategy.store(entry); |
| |
| // update weblog last modified date. date updated by saveWebsite() |
| if(entry.isPublished()) { |
| roller.getWeblogManager().saveWeblog(entry.getWebsite()); |
| } |
| |
| if(entry.isPublished()) { |
| // Queue applicable pings for this update. |
| roller.getAutopingManager().queueApplicableAutoPings(entry); |
| } |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public void removeWeblogEntry(WeblogEntry entry) throws WebloggerException { |
| Weblog weblog = entry.getWebsite(); |
| |
| CommentSearchCriteria csc = new CommentSearchCriteria(); |
| csc.setEntry(entry); |
| |
| // remove comments |
| List<WeblogEntryComment> comments = getComments(csc); |
| for (WeblogEntryComment comment : comments) { |
| this.strategy.remove(comment); |
| } |
| |
| // remove tag & tag aggregates |
| if (entry.getTags() != null) { |
| for (WeblogEntryTag tag : entry.getTags()) { |
| removeWeblogEntryTag(tag); |
| } |
| } |
| |
| // remove attributes |
| if (entry.getEntryAttributes() != null) { |
| for (Iterator<WeblogEntryAttribute> it = entry.getEntryAttributes().iterator(); it.hasNext(); ) { |
| WeblogEntryAttribute att = it.next(); |
| it.remove(); |
| this.strategy.remove(att); |
| } |
| } |
| |
| // remove entry |
| this.strategy.remove(entry); |
| |
| // update weblog last modified date. date updated by saveWebsite() |
| if (entry.isPublished()) { |
| roller.getWeblogManager().saveWeblog(weblog); |
| } |
| |
| // remove entry from cache mapping |
| this.entryAnchorToIdMap.remove(entry.getWebsite().getHandle()+":"+entry.getAnchor()); |
| } |
| |
| private List<WeblogEntry> getNextPrevEntries(WeblogEntry current, String catName, |
| String locale, int maxEntries, boolean next) |
| throws WebloggerException { |
| |
| if (current == null) { |
| LOG.debug("current WeblogEntry cannot be null"); |
| return Collections.emptyList(); |
| } |
| |
| TypedQuery<WeblogEntry> query; |
| WeblogCategory category; |
| |
| List<Object> params = new ArrayList<>(); |
| int size = 0; |
| String queryString = "SELECT e FROM WeblogEntry e WHERE "; |
| StringBuilder whereClause = new StringBuilder(); |
| |
| params.add(size++, current.getWebsite()); |
| whereClause.append("e.website = ?").append(size); |
| |
| params.add(size++, PubStatus.PUBLISHED); |
| whereClause.append(" AND e.status = ?").append(size); |
| |
| if (next) { |
| params.add(size++, current.getPubTime()); |
| whereClause.append(" AND e.pubTime > ?").append(size); |
| } else { |
| // pub time null if current article not yet published, in Draft view |
| if (current.getPubTime() != null) { |
| params.add(size++, current.getPubTime()); |
| whereClause.append(" AND e.pubTime < ?").append(size); |
| } |
| } |
| |
| if (catName != null) { |
| category = getWeblogCategoryByName(current.getWebsite(), catName); |
| if (category != null) { |
| params.add(size++, category); |
| whereClause.append(" AND e.category = ?").append(size); |
| } else { |
| throw new WebloggerException("Cannot find category: " + catName); |
| } |
| } |
| |
| if(locale != null) { |
| params.add(size++, locale + '%'); |
| whereClause.append(" AND e.locale like ?").append(size); |
| } |
| |
| if (next) { |
| whereClause.append(" ORDER BY e.pubTime ASC"); |
| } else { |
| whereClause.append(" ORDER BY e.pubTime DESC"); |
| } |
| query = strategy.getDynamicQuery(queryString + whereClause.toString(), WeblogEntry.class); |
| for (int i=0; i<params.size(); i++) { |
| query.setParameter(i+1, params.get(i)); |
| } |
| query.setMaxResults(maxEntries); |
| |
| return query.getResultList(); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public List<WeblogCategory> getWeblogCategories(Weblog website) |
| throws WebloggerException { |
| if (website == null) { |
| throw new WebloggerException("website is null"); |
| } |
| |
| TypedQuery<WeblogCategory> q = strategy.getNamedQuery( |
| "WeblogCategory.getByWeblog", WeblogCategory.class); |
| q.setParameter(1, website); |
| return q.getResultList(); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public List<WeblogEntry> getWeblogEntries(WeblogEntrySearchCriteria wesc) throws WebloggerException { |
| |
| WeblogCategory cat = null; |
| if (StringUtils.isNotEmpty(wesc.getCatName()) && wesc.getWeblog() != null) { |
| cat = getWeblogCategoryByName(wesc.getWeblog(), wesc.getCatName()); |
| } |
| |
| List<Object> params = new ArrayList<>(); |
| int size = 0; |
| StringBuilder queryString = new StringBuilder(); |
| |
| if (wesc.getTags() == null || wesc.getTags().isEmpty()) { |
| queryString.append("SELECT e FROM WeblogEntry e WHERE "); |
| } else { |
| queryString.append("SELECT e FROM WeblogEntry e JOIN e.tags t WHERE "); |
| queryString.append("("); |
| for (int i = 0; i < wesc.getTags().size(); i++) { |
| if (i != 0) { |
| queryString.append(" OR "); |
| } |
| params.add(size++, wesc.getTags().get(i)); |
| queryString.append(" t.name = ?").append(size); |
| } |
| queryString.append(") AND "); |
| } |
| |
| if (wesc.getWeblog() != null) { |
| params.add(size++, wesc.getWeblog().getId()); |
| queryString.append("e.website.id = ?").append(size); |
| } else { |
| params.add(size++, Boolean.TRUE); |
| queryString.append("e.website.visible = ?").append(size); |
| } |
| |
| if (wesc.getUser() != null) { |
| params.add(size++, wesc.getUser().getUserName()); |
| queryString.append(" AND e.creatorUserName = ?").append(size); |
| } |
| |
| if (wesc.getStartDate() != null) { |
| Timestamp start = new Timestamp(wesc.getStartDate().getTime()); |
| params.add(size++, start); |
| queryString.append(" AND e.pubTime >= ?").append(size); |
| } |
| |
| if (wesc.getEndDate() != null) { |
| Timestamp end = new Timestamp(wesc.getEndDate().getTime()); |
| params.add(size++, end); |
| queryString.append(" AND e.pubTime <= ?").append(size); |
| } |
| |
| if (cat != null) { |
| params.add(size++, cat.getId()); |
| queryString.append(" AND e.category.id = ?").append(size); |
| } |
| |
| if (wesc.getStatus() != null) { |
| params.add(size++, wesc.getStatus()); |
| queryString.append(" AND e.status = ?").append(size); |
| } |
| |
| if (wesc.getLocale() != null) { |
| params.add(size++, wesc.getLocale() + '%'); |
| queryString.append(" AND e.locale like ?").append(size); |
| } |
| |
| if (StringUtils.isNotEmpty(wesc.getText())) { |
| params.add(size++, '%' + wesc.getText() + '%'); |
| queryString.append(" AND ( e.text LIKE ?").append(size); |
| queryString.append(" OR e.summary LIKE ?").append(size); |
| queryString.append(" OR e.title LIKE ?").append(size); |
| queryString.append(") "); |
| } |
| |
| if (wesc.getSortBy() != null && wesc.getSortBy().equals(WeblogEntrySearchCriteria.SortBy.UPDATE_TIME)) { |
| queryString.append(" ORDER BY e.updateTime "); |
| } else { |
| queryString.append(" ORDER BY e.pubTime "); |
| } |
| |
| if (wesc.getSortOrder() != null && wesc.getSortOrder().equals(WeblogEntrySearchCriteria.SortOrder.ASCENDING)) { |
| queryString.append("ASC "); |
| } else { |
| queryString.append("DESC "); |
| } |
| |
| |
| TypedQuery<WeblogEntry> query = strategy.getDynamicQuery(queryString.toString(), WeblogEntry.class); |
| for (int i=0; i<params.size(); i++) { |
| query.setParameter(i+1, params.get(i)); |
| } |
| |
| setFirstMax( query, wesc.getOffset(), wesc.getMaxResults() ); |
| return query.getResultList(); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public List<WeblogEntry> getWeblogEntriesPinnedToMain(Integer max) |
| throws WebloggerException { |
| TypedQuery<WeblogEntry> query = strategy.getNamedQuery( |
| "WeblogEntry.getByPinnedToMain&statusOrderByPubTimeDesc", WeblogEntry.class); |
| query.setParameter(1, Boolean.TRUE); |
| query.setParameter(2, PubStatus.PUBLISHED); |
| if (max != null) { |
| query.setMaxResults(max); |
| } |
| return query.getResultList(); |
| } |
| |
| @Override |
| public void removeWeblogEntryAttribute(String name, WeblogEntry entry) |
| throws WebloggerException { |
| |
| // seems silly, why is this not done in WeblogEntry? |
| |
| for (Iterator<WeblogEntryAttribute> it = entry.getEntryAttributes().iterator(); it.hasNext();) { |
| WeblogEntryAttribute entryAttribute = it.next(); |
| if (entryAttribute.getName().equals(name)) { |
| |
| //Remove it from database |
| this.strategy.remove(entryAttribute); |
| |
| //Remove it from the collection |
| it.remove(); |
| } |
| } |
| } |
| |
| private void removeWeblogEntryTag(WeblogEntryTag tag) throws WebloggerException { |
| if (tag.getWeblogEntry().isPublished()) { |
| updateTagCount(tag.getName(), tag.getWeblogEntry().getWebsite(), -1); |
| } |
| this.strategy.remove(tag); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public WeblogEntry getWeblogEntryByAnchor(Weblog website, |
| String anchor) throws WebloggerException { |
| |
| if (website == null) { |
| throw new WebloggerException("Website is null"); |
| } |
| |
| if (anchor == null) { |
| throw new WebloggerException("Anchor is null"); |
| } |
| |
| // mapping key is combo of weblog + anchor |
| String mappingKey = website.getHandle() + ":" + anchor; |
| |
| // check cache first |
| // NOTE: if we ever allow changing anchors then this needs updating |
| if(this.entryAnchorToIdMap.containsKey(mappingKey)) { |
| |
| WeblogEntry entry = this.getWeblogEntry(this.entryAnchorToIdMap.get(mappingKey)); |
| if(entry != null) { |
| LOG.debug("entryAnchorToIdMap CACHE HIT - " + mappingKey); |
| return entry; |
| } else { |
| // mapping hit with lookup miss? mapping must be old, remove it |
| this.entryAnchorToIdMap.remove(mappingKey); |
| } |
| } |
| |
| // cache failed, do lookup |
| TypedQuery<WeblogEntry> q = strategy.getNamedQuery( |
| "WeblogEntry.getByWebsite&AnchorOrderByPubTimeDesc", WeblogEntry.class); |
| q.setParameter(1, website); |
| q.setParameter(2, anchor); |
| WeblogEntry entry; |
| try { |
| entry = q.getSingleResult(); |
| } catch (NoResultException e) { |
| entry = null; |
| } |
| |
| // add mapping to cache |
| if(entry != null) { |
| LOG.debug("entryAnchorToIdMap CACHE MISS - " + mappingKey); |
| this.entryAnchorToIdMap.put(mappingKey, entry.getId()); |
| } |
| return entry; |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public String createAnchor(WeblogEntry entry) throws WebloggerException { |
| // Check for uniqueness of anchor |
| String base = entry.createAnchorBase(); |
| String name = base; |
| int count = 0; |
| |
| while (true) { |
| if (count > 0) { |
| name = base + count; |
| } |
| |
| TypedQuery<WeblogEntry> q = strategy.getNamedQuery( |
| "WeblogEntry.getByWebsite&Anchor", WeblogEntry.class); |
| q.setParameter(1, entry.getWebsite()); |
| q.setParameter(2, name); |
| List<WeblogEntry> results = q.getResultList(); |
| |
| if (results.isEmpty()) { |
| break; |
| } else { |
| count++; |
| } |
| } |
| return name; |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public boolean isDuplicateWeblogCategoryName(WeblogCategory cat) |
| throws WebloggerException { |
| return (getWeblogCategoryByName( |
| cat.getWeblog(), cat.getName()) != null); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public boolean isWeblogCategoryInUse(WeblogCategory cat) |
| throws WebloggerException { |
| if (cat.getWeblog().getBloggerCategory().equals(cat)) { |
| return true; |
| } |
| TypedQuery<WeblogEntry> q = strategy.getNamedQuery("WeblogEntry.getByCategory", WeblogEntry.class); |
| q.setParameter(1, cat); |
| int entryCount = q.getResultList().size(); |
| return entryCount > 0; |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public List<WeblogEntryComment> getComments(CommentSearchCriteria csc) throws WebloggerException { |
| |
| List<Object> params = new ArrayList<>(); |
| int size = 0; |
| StringBuilder queryString = new StringBuilder(); |
| queryString.append("SELECT c FROM WeblogEntryComment c "); |
| |
| StringBuilder whereClause = new StringBuilder(); |
| if (csc.getEntry() != null) { |
| params.add(size++, csc.getEntry()); |
| whereClause.append("c.weblogEntry = ?").append(size); |
| } else if (csc.getWeblog() != null) { |
| params.add(size++, csc.getWeblog()); |
| whereClause.append("c.weblogEntry.website = ?").append(size); |
| } |
| |
| if (csc.getSearchText() != null) { |
| params.add(size++, "%" + csc.getSearchText().toUpperCase() + "%"); |
| appendConjuctionToWhereclause(whereClause, "upper(c.content) LIKE ?").append(size); |
| } |
| |
| if (csc.getStartDate() != null) { |
| Timestamp start = new Timestamp(csc.getStartDate().getTime()); |
| params.add(size++, start); |
| appendConjuctionToWhereclause(whereClause, "c.postTime >= ?").append(size); |
| } |
| |
| if (csc.getEndDate() != null) { |
| Timestamp end = new Timestamp(csc.getEndDate().getTime()); |
| params.add(size++, end); |
| appendConjuctionToWhereclause(whereClause, "c.postTime <= ?").append(size); |
| } |
| |
| if (csc.getStatus() != null) { |
| params.add(size++, csc.getStatus()); |
| appendConjuctionToWhereclause(whereClause, "c.status = ?").append(size); |
| } |
| |
| if(whereClause.length() != 0) { |
| queryString.append(" WHERE ").append(whereClause); |
| } |
| if (csc.isReverseChrono()) { |
| queryString.append(" ORDER BY c.postTime DESC"); |
| } else { |
| queryString.append(" ORDER BY c.postTime ASC"); |
| } |
| |
| TypedQuery<WeblogEntryComment> query = strategy.getDynamicQuery(queryString.toString(), WeblogEntryComment.class); |
| setFirstMax( query, csc.getOffset(), csc.getMaxResults()); |
| for (int i=0; i<params.size(); i++) { |
| query.setParameter(i+1, params.get(i)); |
| } |
| return query.getResultList(); |
| |
| } |
| |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public int removeMatchingComments( |
| Weblog weblog, |
| WeblogEntry entry, |
| String searchString, |
| Date startDate, |
| Date endDate, |
| ApprovalStatus status) throws WebloggerException { |
| |
| // TODO dynamic bulk delete query: I'd MUCH rather use a bulk delete, |
| // but MySQL says "General error, message from server: "You can't |
| // specify target table 'roller_comment' for update in FROM clause" |
| |
| CommentSearchCriteria csc = new CommentSearchCriteria(); |
| csc.setWeblog(weblog); |
| csc.setEntry(entry); |
| csc.setSearchText(searchString); |
| csc.setStartDate(startDate); |
| csc.setEndDate(endDate); |
| csc.setStatus(status); |
| |
| List<WeblogEntryComment> comments = getComments(csc); |
| int count = 0; |
| for (WeblogEntryComment comment : comments) { |
| removeComment(comment); |
| count++; |
| } |
| return count; |
| } |
| |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public WeblogCategory getWeblogCategory(String id) |
| throws WebloggerException { |
| return (WeblogCategory) this.strategy.load( |
| WeblogCategory.class, id); |
| } |
| |
| //--------------------------------------------- WeblogCategory Queries |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public WeblogCategory getWeblogCategoryByName(Weblog weblog, |
| String categoryName) throws WebloggerException { |
| TypedQuery<WeblogCategory> q = strategy.getNamedQuery( |
| "WeblogCategory.getByWeblog&Name", WeblogCategory.class); |
| q.setParameter(1, weblog); |
| q.setParameter(2, categoryName); |
| try { |
| return q.getSingleResult(); |
| } catch (NoResultException e) { |
| return null; |
| } |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public WeblogEntryComment getComment(String id) throws WebloggerException { |
| return (WeblogEntryComment) this.strategy.load(WeblogEntryComment.class, id); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public WeblogEntry getWeblogEntry(String id) throws WebloggerException { |
| return (WeblogEntry)strategy.load(WeblogEntry.class, id); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public Map<Date, List<WeblogEntry>> getWeblogEntryObjectMap(WeblogEntrySearchCriteria wesc) throws WebloggerException { |
| TreeMap<Date, List<WeblogEntry>> map = new TreeMap<>(Collections.reverseOrder()); |
| |
| List<WeblogEntry> entries = getWeblogEntries(wesc); |
| |
| Calendar cal = Calendar.getInstance(); |
| if (wesc.getWeblog() != null) { |
| cal.setTimeZone(wesc.getWeblog().getTimeZoneInstance()); |
| } |
| |
| for (WeblogEntry entry : entries) { |
| Date sDate = DateUtil.getNoonOfDay(entry.getPubTime(), cal); |
| List<WeblogEntry> dayEntries = map.computeIfAbsent(sDate, k -> new ArrayList<>()); |
| dayEntries.add(entry); |
| } |
| return map; |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public Map<Date, String> getWeblogEntryStringMap(WeblogEntrySearchCriteria wesc) throws WebloggerException { |
| TreeMap<Date, String> map = new TreeMap<>(Collections.reverseOrder()); |
| |
| List<WeblogEntry> entries = getWeblogEntries(wesc); |
| |
| Calendar cal = Calendar.getInstance(); |
| SimpleDateFormat formatter = DateUtil.get8charDateFormat(); |
| if (wesc.getWeblog() != null) { |
| TimeZone tz = wesc.getWeblog().getTimeZoneInstance(); |
| cal.setTimeZone(tz); |
| formatter.setTimeZone(tz); |
| } |
| |
| for (WeblogEntry entry : entries) { |
| Date sDate = DateUtil.getNoonOfDay(entry.getPubTime(), cal); |
| if (map.get(sDate) == null) { |
| map.put(sDate, formatter.format(sDate)); |
| } |
| } |
| return map; |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public List<StatCount> getMostCommentedWeblogEntries(Weblog website, |
| Date startDate, Date endDate, int offset, |
| int length) throws WebloggerException { |
| TypedQuery<WeblogEntryComment> query; |
| List<WeblogEntryComment> queryResults; |
| |
| Timestamp end = new Timestamp(endDate != null? endDate.getTime() : new Date().getTime()); |
| |
| if (website != null) { |
| if (startDate != null) { |
| Timestamp start = new Timestamp(startDate.getTime()); |
| query = strategy.getNamedQuery( |
| "WeblogEntryComment.getMostCommentedWeblogEntryByWebsite&EndDate&StartDate", |
| WeblogEntryComment.class); |
| query.setParameter(1, website); |
| query.setParameter(2, end); |
| query.setParameter(3, start); |
| } else { |
| query = strategy.getNamedQuery( |
| "WeblogEntryComment.getMostCommentedWeblogEntryByWebsite&EndDate", WeblogEntryComment.class); |
| query.setParameter(1, website); |
| query.setParameter(2, end); |
| } |
| } else { |
| if (startDate != null) { |
| Timestamp start = new Timestamp(startDate.getTime()); |
| query = strategy.getNamedQuery( |
| "WeblogEntryComment.getMostCommentedWeblogEntryByEndDate&StartDate", WeblogEntryComment.class); |
| query.setParameter(1, end); |
| query.setParameter(2, start); |
| } else { |
| query = strategy.getNamedQuery( |
| "WeblogEntryComment.getMostCommentedWeblogEntryByEndDate", WeblogEntryComment.class); |
| query.setParameter(1, end); |
| } |
| } |
| setFirstMax( query, offset, length); |
| queryResults = query.getResultList(); |
| List<StatCount> results = new ArrayList<>(); |
| if (queryResults != null) { |
| for (Object obj : queryResults) { |
| Object[] row = (Object[]) obj; |
| StatCount sc = new StatCount( |
| (String)row[1], // weblog handle |
| (String)row[2], // entry anchor |
| (String)row[3], // entry title |
| "statCount.weblogEntryCommentCountType", // stat desc |
| ((Long)row[0])); // count |
| sc.setWeblogHandle((String)row[1]); |
| results.add(sc); |
| } |
| } |
| // Original query ordered by desc count. |
| // JPA QL doesn't allow queries to be ordered by agregates; do it in memory |
| results.sort(STAT_COUNT_COUNT_REVERSE_COMPARATOR); |
| |
| return results; |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public WeblogEntry getNextEntry(WeblogEntry current, |
| String catName, String locale) throws WebloggerException { |
| WeblogEntry entry = null; |
| List<WeblogEntry> entryList = getNextPrevEntries(current, catName, locale, 1, true); |
| if (entryList != null && !entryList.isEmpty()) { |
| entry = entryList.get(0); |
| } |
| return entry; |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public WeblogEntry getPreviousEntry(WeblogEntry current, |
| String catName, String locale) throws WebloggerException { |
| WeblogEntry entry = null; |
| List<WeblogEntry> entryList = getNextPrevEntries(current, catName, locale, 1, false); |
| if (entryList != null && !entryList.isEmpty()) { |
| entry = entryList.get(0); |
| } |
| return entry; |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public void release() {} |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public void applyCommentDefaultsToEntries(Weblog website) |
| throws WebloggerException { |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("applyCommentDefaults"); |
| } |
| |
| // TODO: Non-standard JPA bulk update, using parameter values in set clause |
| Query q = strategy.getNamedUpdate( |
| "WeblogEntry.updateAllowComments&CommentDaysByWebsite"); |
| q.setParameter(1, website.getDefaultAllowComments()); |
| q.setParameter(2, website.getDefaultCommentDays()); |
| q.setParameter(3, website); |
| q.executeUpdate(); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public List<TagStat> getPopularTags(Weblog website, Date startDate, int offset, int limit) |
| throws WebloggerException { |
| TypedQuery<TagStat> query; |
| List<TagStat> queryResults; |
| |
| if (website != null) { |
| if (startDate != null) { |
| Timestamp start = new Timestamp(startDate.getTime()); |
| query = strategy.getNamedQuery( |
| "WeblogEntryTagAggregate.getPopularTagsByWebsite&StartDate", TagStat.class); |
| query.setParameter(1, website); |
| query.setParameter(2, start); |
| } else { |
| query = strategy.getNamedQuery( |
| "WeblogEntryTagAggregate.getPopularTagsByWebsite", TagStat.class); |
| query.setParameter(1, website); |
| } |
| } else { |
| if (startDate != null) { |
| Timestamp start = new Timestamp(startDate.getTime()); |
| query = strategy.getNamedQuery( |
| "WeblogEntryTagAggregate.getPopularTagsByWebsiteNull&StartDate", TagStat.class); |
| query.setParameter(1, start); |
| } else { |
| query = strategy.getNamedQuery( |
| "WeblogEntryTagAggregate.getPopularTagsByWebsiteNull", TagStat.class); |
| } |
| } |
| setFirstMax( query, offset, limit); |
| queryResults = query.getResultList(); |
| |
| double min = Integer.MAX_VALUE; |
| double max = Integer.MIN_VALUE; |
| |
| List<TagStat> results = new ArrayList<>(limit >= 0 ? limit : 25); |
| |
| if (queryResults != null) { |
| for (Object obj : queryResults) { |
| Object[] row = (Object[]) obj; |
| TagStat t = new TagStat(); |
| t.setName((String) row[0]); |
| t.setCount(((Number) row[1]).intValue()); |
| |
| min = Math.min(min, t.getCount()); |
| max = Math.max(max, t.getCount()); |
| results.add(t); |
| } |
| } |
| |
| min = Math.log(1+min); |
| max = Math.log(1+max); |
| |
| double range = Math.max(.01, max - min) * 1.0001; |
| |
| for (TagStat t : results) { |
| t.setIntensity((int) (1 + Math.floor(5 * (Math.log(1+t.getCount()) - min) / range))); |
| } |
| |
| // sort results by name, because query had to sort by total |
| results.sort(TAG_STAT_NAME_COMPARATOR); |
| |
| return results; |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public List<TagStat> getTags(Weblog website, String sortBy, |
| String startsWith, int offset, int limit) throws WebloggerException { |
| Query query; |
| List<?> queryResults; |
| boolean sortByName = sortBy == null || !sortBy.equals("count"); |
| |
| List<Object> params = new ArrayList<>(); |
| int size = 0; |
| StringBuilder queryString = new StringBuilder(); |
| queryString.append("SELECT w.name, SUM(w.total) FROM WeblogEntryTagAggregate w WHERE "); |
| |
| if (website != null) { |
| params.add(size++, website.getId()); |
| queryString.append(" w.weblog.id = ?").append(size); |
| } else { |
| queryString.append(" w.weblog IS NULL"); |
| } |
| |
| if (startsWith != null && startsWith.length() > 0) { |
| params.add(size++, startsWith + '%'); |
| queryString.append(" AND w.name LIKE ?").append(size); |
| } |
| |
| if (sortBy != null && sortBy.equals("count")) { |
| sortBy = "w.total DESC"; |
| } else { |
| sortBy = "w.name"; |
| } |
| queryString.append(" GROUP BY w.name, w.total ORDER BY ").append(sortBy); |
| |
| query = strategy.getDynamicQuery(queryString.toString()); |
| for (int i=0; i<params.size(); i++) { |
| query.setParameter(i+1, params.get(i)); |
| } |
| setFirstMax( query, offset, limit); |
| queryResults = query.getResultList(); |
| |
| List<TagStat> results = new ArrayList<>(); |
| if (queryResults != null) { |
| for (Object obj : queryResults) { |
| Object[] row = (Object[]) obj; |
| TagStat ce = new TagStat(); |
| ce.setName((String) row[0]); |
| // The JPA query retrieves SUM(w.total) always as long |
| ce.setCount(((Long) row[1]).intValue()); |
| results.add(ce); |
| } |
| } |
| |
| if (sortByName) { |
| results.sort(TAG_STAT_NAME_COMPARATOR); |
| } else { |
| results.sort(TAG_STAT_COUNT_REVERSE_COMPARATOR); |
| } |
| |
| return results; |
| } |
| |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public boolean getTagComboExists(List<String> tags, Weblog weblog) throws WebloggerException{ |
| |
| if (tags == null || tags.isEmpty()) { |
| return false; |
| } |
| |
| StringBuilder queryString = new StringBuilder(); |
| queryString.append("SELECT DISTINCT w.name "); |
| queryString.append("FROM WeblogEntryTagAggregate w WHERE w.name IN ("); |
| // Append tags as parameter markers to avoid potential escaping issues |
| // The IN clause would be of form (?1, ?2, ?3, ..) |
| List<Object> params = new ArrayList<>(tags.size() + 1); |
| final String paramSeparator = ", "; |
| int i; |
| for (i=0; i < tags.size(); i++) { |
| queryString.append('?').append(i+1).append(paramSeparator); |
| params.add(tags.get(i)); |
| } |
| |
| // Remove the trailing paramSeparator |
| queryString.delete(queryString.length() - paramSeparator.length(), |
| queryString.length()); |
| // Close the brace of IN clause |
| queryString.append(')'); |
| |
| if(weblog != null) { |
| queryString.append(" AND w.weblog = ?").append(i+1); |
| params.add(weblog); |
| } else { |
| queryString.append(" AND w.weblog IS NULL"); |
| } |
| |
| TypedQuery<String> q = strategy.getDynamicQuery(queryString.toString(), String.class); |
| for (int j=0; j<params.size(); j++) { |
| q.setParameter(j+1, params.get(j)); |
| } |
| List<String> results = q.getResultList(); |
| |
| //TODO: DatamapperPort: Since we are only interested in knowing whether |
| //results.size() == tags.size(). This query can be optimized to just fetch COUNT |
| //instead of objects as done currently |
| return (results != null && results.size() == tags.size()); |
| } |
| |
| /** |
| * This method maintains the tag aggregate table up-to-date with total counts. More |
| * specifically every time this method is called it will act upon exactly two rows |
| * in the database (tag,website,count), one with website matching the argument passed |
| * and one where website is null. If the count ever reaches zero, the row must be deleted. |
| * |
| * @param name The tag name |
| * @param website The website to used when updating the stats. |
| * @param amount The amount to increment the tag count (it can be positive or negative). |
| * @throws WebloggerException |
| */ |
| private void updateTagCount(String name, Weblog website, int amount) |
| throws WebloggerException { |
| if (amount == 0) { |
| throw new WebloggerException("Tag increment amount cannot be zero."); |
| } |
| |
| if (website == null) { |
| throw new WebloggerException("Website cannot be NULL."); |
| } |
| |
| // The reason why add order lastUsed desc is to make sure we keep picking the most recent |
| // one in the case where we have multiple rows (clustered environment) |
| // eventually that second entry will have a very low total (most likely 1) and |
| // won't matter |
| TypedQuery<WeblogEntryTagAggregate> weblogQuery = strategy.getNamedQuery( |
| "WeblogEntryTagAggregate.getByName&WebsiteOrderByLastUsedDesc", WeblogEntryTagAggregate.class); |
| weblogQuery.setParameter(1, name); |
| weblogQuery.setParameter(2, website); |
| WeblogEntryTagAggregate weblogTagData; |
| try { |
| weblogTagData = weblogQuery.getSingleResult(); |
| } catch (NoResultException e) { |
| weblogTagData = null; |
| } |
| |
| TypedQuery<WeblogEntryTagAggregate> siteQuery = strategy.getNamedQuery( |
| "WeblogEntryTagAggregate.getByName&WebsiteNullOrderByLastUsedDesc", WeblogEntryTagAggregate.class); |
| siteQuery.setParameter(1, name); |
| WeblogEntryTagAggregate siteTagData; |
| try { |
| siteTagData = siteQuery.getSingleResult(); |
| } catch (NoResultException e) { |
| siteTagData = null; |
| } |
| Timestamp lastUsed = new Timestamp((new Date()).getTime()); |
| |
| // create it only if we are going to need it. |
| if (weblogTagData == null && amount > 0) { |
| weblogTagData = new WeblogEntryTagAggregate(null, website, name, amount); |
| weblogTagData.setLastUsed(lastUsed); |
| strategy.store(weblogTagData); |
| |
| } else if (weblogTagData != null) { |
| weblogTagData.setTotal(weblogTagData.getTotal() + amount); |
| weblogTagData.setLastUsed(lastUsed); |
| strategy.store(weblogTagData); |
| } |
| |
| // create it only if we are going to need it. |
| if (siteTagData == null && amount > 0) { |
| siteTagData = new WeblogEntryTagAggregate(null, null, name, amount); |
| siteTagData.setLastUsed(lastUsed); |
| strategy.store(siteTagData); |
| |
| } else if (siteTagData != null) { |
| siteTagData.setTotal(siteTagData.getTotal() + amount); |
| siteTagData.setLastUsed(lastUsed); |
| strategy.store(siteTagData); |
| } |
| |
| // delete all bad counts |
| Query removeq = strategy.getNamedUpdate( |
| "WeblogEntryTagAggregate.removeByTotalLessEqual"); |
| removeq.setParameter(1, 0); |
| removeq.executeUpdate(); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public WeblogHitCount getHitCount(String id) throws WebloggerException { |
| |
| // do lookup |
| return (WeblogHitCount) strategy.load(WeblogHitCount.class, id); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public WeblogHitCount getHitCountByWeblog(Weblog weblog) |
| throws WebloggerException { |
| TypedQuery<WeblogHitCount> q = strategy.getNamedQuery("WeblogHitCount.getByWeblog", WeblogHitCount.class); |
| q.setParameter(1, weblog); |
| try { |
| return q.getSingleResult(); |
| } catch (NoResultException e) { |
| return null; |
| } |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public List<WeblogHitCount> getHotWeblogs(int sinceDays, int offset, int length) |
| throws WebloggerException { |
| |
| // figure out start date |
| Date startDate = getStartDateNow(sinceDays); |
| |
| TypedQuery<WeblogHitCount> query; |
| query = strategy.getNamedQuery( |
| "WeblogHitCount.getByWeblogEnabledTrueAndActiveTrue&DailyHitsGreaterThenZero&WeblogLastModifiedGreaterOrderByDailyHitsDesc", |
| WeblogHitCount.class); |
| query.setParameter(1, startDate); |
| setFirstMax( query, offset, length ); |
| return query.getResultList(); |
| } |
| |
| |
| private static void setFirstMax( Query query, int offset, int length ) { |
| if (offset != 0) { |
| query.setFirstResult(offset); |
| } |
| if (length != -1) { |
| query.setMaxResults(length); |
| } |
| } |
| |
| |
| public static Date getStartDateNow(int sinceDays) { |
| Calendar cal = Calendar.getInstance(); |
| cal.setTime(new Date()); |
| cal.add(Calendar.DATE, -1 * sinceDays); |
| return cal.getTime(); |
| } |
| |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public void saveHitCount(WeblogHitCount hitCount) throws WebloggerException { |
| this.strategy.store(hitCount); |
| } |
| |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public void removeHitCount(WeblogHitCount hitCount) throws WebloggerException { |
| this.strategy.remove(hitCount); |
| } |
| |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public void incrementHitCount(Weblog weblog, int amount) |
| throws WebloggerException { |
| |
| if(amount == 0) { |
| throw new WebloggerException("Tag increment amount cannot be zero."); |
| } |
| |
| if(weblog == null) { |
| throw new WebloggerException("Website cannot be NULL."); |
| } |
| |
| TypedQuery<WeblogHitCount> q = strategy.getNamedQuery("WeblogHitCount.getByWeblog", WeblogHitCount.class); |
| q.setParameter(1, weblog); |
| WeblogHitCount hitCount; |
| try { |
| hitCount = q.getSingleResult(); |
| } catch (NoResultException e) { |
| hitCount = null; |
| } |
| |
| // create it if it doesn't exist |
| if(hitCount == null && amount > 0) { |
| hitCount = new WeblogHitCount(); |
| hitCount.setWeblog(weblog); |
| hitCount.setDailyHits(amount); |
| strategy.store(hitCount); |
| } else if(hitCount != null) { |
| hitCount.setDailyHits(hitCount.getDailyHits() + amount); |
| strategy.store(hitCount); |
| } |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public void resetAllHitCounts() throws WebloggerException { |
| Query q = strategy.getNamedUpdate("WeblogHitCount.updateDailyHitCountZero"); |
| q.executeUpdate(); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public void resetHitCount(Weblog weblog) throws WebloggerException { |
| TypedQuery<WeblogHitCount> q = strategy.getNamedQuery("WeblogHitCount.getByWeblog", WeblogHitCount.class); |
| q.setParameter(1, weblog); |
| WeblogHitCount hitCount; |
| try { |
| hitCount = q.getSingleResult(); |
| hitCount.setDailyHits(0); |
| strategy.store(hitCount); |
| } catch (NoResultException e) { |
| // ignore: no hit count for weblog |
| } |
| |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public long getCommentCount() throws WebloggerException { |
| TypedQuery<Long> q = strategy.getNamedQuery( |
| "WeblogEntryComment.getCountAllDistinctByStatus", Long.class); |
| q.setParameter(1, ApprovalStatus.APPROVED); |
| return q.getResultList().get(0); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public long getCommentCount(Weblog website) throws WebloggerException { |
| TypedQuery<Long> q = strategy.getNamedQuery( |
| "WeblogEntryComment.getCountDistinctByWebsite&Status", Long.class); |
| q.setParameter(1, website); |
| q.setParameter(2, ApprovalStatus.APPROVED); |
| return q.getResultList().get(0); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public long getEntryCount() throws WebloggerException { |
| TypedQuery<Long> q = strategy.getNamedQuery( |
| "WeblogEntry.getCountDistinctByStatus", Long.class); |
| q.setParameter(1, PubStatus.PUBLISHED); |
| return q.getResultList().get(0); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| @Override |
| public long getEntryCount(Weblog website) throws WebloggerException { |
| TypedQuery<Long> q = strategy.getNamedQuery( |
| "WeblogEntry.getCountDistinctByStatus&Website", Long.class); |
| q.setParameter(1, PubStatus.PUBLISHED); |
| q.setParameter(2, website); |
| return q.getResultList().get(0); |
| } |
| |
| /** |
| * Appends given expression to given whereClause. If whereClause already |
| * has other conditions, an " AND " is also appended before appending |
| * the expression |
| * @param whereClause The given where Clauuse |
| * @param expression The given expression |
| * @return the whereClause. |
| */ |
| private static StringBuilder appendConjuctionToWhereclause(StringBuilder whereClause, |
| String expression) { |
| if (whereClause.length() != 0 && expression.length() != 0) { |
| whereClause.append(" AND "); |
| } |
| return whereClause.append(expression); |
| } |
| |
| } |