Java tutorial
/* * Copyright 2009 Kantega AS * * Licensed 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. */ package no.kantega.publishing.common; import no.kantega.commons.exception.SystemException; import no.kantega.commons.util.StringHelper; import no.kantega.publishing.api.cache.SiteCache; import no.kantega.publishing.api.content.ContentAO; import no.kantega.publishing.api.content.ContentIdHelper; import no.kantega.publishing.api.content.ContentIdentifier; import no.kantega.publishing.api.content.ContentIdentifierDao; import no.kantega.publishing.api.content.Language; import no.kantega.publishing.api.model.Site; import no.kantega.publishing.common.ao.AssociationAO; import no.kantega.publishing.common.data.Association; import no.kantega.publishing.common.data.Content; import no.kantega.publishing.common.data.ContentQuery; import no.kantega.publishing.common.data.SortOrder; import no.kantega.publishing.common.data.enums.AssociationType; import no.kantega.publishing.common.data.enums.ContentProperty; import no.kantega.publishing.common.exception.ContentNotFoundException; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.support.JdbcDaoSupport; import org.springframework.web.bind.ServletRequestBindingException; import org.springframework.web.bind.ServletRequestUtils; import org.springframework.web.context.ServletContextAware; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import static no.kantega.publishing.api.ContentUtil.tryGetFromRequest; import static org.apache.commons.lang3.StringUtils.defaultIfBlank; public class ContentIdHelperImpl extends JdbcDaoSupport implements ContentIdHelper, ServletContextAware { private static final Logger log = LoggerFactory.getLogger(ContentIdHelperImpl.class); private static final Pattern dotPattern = Pattern.compile("\\.\\."); private final int defaultContentID = -1; private final int defaultSiteId = -1; private final int defaultContextId = -1; private final int defaultVersion = -1; private final Pattern siteIdPattern = Pattern.compile(".*siteId=(?<siteId>\\d+).*"); private final Pattern thisIdPattern = Pattern.compile(".*thisId=(?<thisId>\\d+).*"); @Autowired private SiteCache siteCache; @Autowired private ContentAO contentAO; @Autowired private ContentIdentifierDao contentIdentifierDao; public Pattern CONTENT_URL_PATTERN; @Override public ContentIdentifier findRelativeContentIdentifier(Content context, String expr) throws SystemException, ContentNotFoundException { if (context == null || expr == null) { return null; } if (expr.contains("..")) { // Hent fra N niver lengre opp if (expr.charAt(expr.length() - 1) != '/') { expr += "/"; } Association association = context.getAssociation(); String path = association.getPath(); if (path == null || path.length() == 0) { // Finn path'en int parentId = association.getParentAssociationId(); path = AssociationHelper.getPathForId(parentId); } int[] pathElements = StringHelper.getInts(path, "/"); String[] exprPathElements = dotPattern.split(expr); int exprLength = exprPathElements.length - 1; if (exprLength > pathElements.length) { throw new ContentNotFoundException(expr); } ContentIdentifier cid = ContentIdentifier .fromAssociationId(pathElements[pathElements.length - exprLength]); assureContentIdAndAssociationIdSet(cid); cid.setLanguage(context.getLanguage()); return cid; } else if (expr.equalsIgnoreCase(".")) { // Hent fra denne siden ContentIdentifier cid = ContentIdentifier .fromAssociationId(context.getAssociation().getAssociationId()); cid.setLanguage(context.getLanguage()); assureContentIdAndAssociationIdSet(cid); return cid; } else if (expr.equalsIgnoreCase("group")) { // Hent fra group ContentIdentifier cid = ContentIdentifier.fromContentId(context.getGroupId()); cid.setLanguage(context.getLanguage()); assureContentIdAndAssociationIdSet(cid); return cid; } else if (expr.startsWith("/+")) { // Hent fra root + niv n int level = Integer.parseInt(expr.substring("/+".length(), expr.length())); String path = context.getAssociation().getPath() + context.getAssociation().getId() + "/"; int[] pathElements = StringHelper.getInts(path, "/"); if (level > pathElements.length) { level = pathElements.length; } ContentIdentifier contentIdentifier = ContentIdentifier.fromAssociationId(pathElements[level]); assureContentIdAndAssociationIdSet(contentIdentifier); return contentIdentifier; } else if (expr.equalsIgnoreCase("next") || expr.equalsIgnoreCase("previous")) { boolean next = expr.equalsIgnoreCase("next"); Association association = context.getAssociation(); ContentIdentifier parent = ContentIdentifier.fromAssociationId(association.getParentAssociationId()); ContentQuery query = new ContentQuery(); query.setAssociatedId(parent); query.setAssociationCategory(association.getCategory()); query.setSortOrder(new SortOrder(ContentProperty.PRIORITY, false)); List<Content> children = contentAO.getContentList(query, false); for (int i = 0; i < children.size(); i++) { Content c = children.get(i); if (c.getAssociation().getId() == context.getAssociation().getId()) { if (next) { if (i < children.size() - 1) { return children.get(i + 1).getContentIdentifier(); } else { return null; } } else { if (i > 0) { return children.get(i - 1).getContentIdentifier(); } else { return null; } } } } return null; } else { return findContentIdentifier(context.getAssociation().getSiteId(), expr); } } /** * @param siteId - Site * @param url - Url/alias, e.g. /nyheter/ * @return ContentIdentifier for the given site and url. * @throws no.kantega.publishing.common.exception.ContentNotFoundException if no Content is found. * @throws no.kantega.commons.exception.SystemException */ private ContentIdentifier findContentIdentifier(int siteId, String url) throws ContentNotFoundException, SystemException { if (url == null) { throw new ContentNotFoundException(""); } Matcher contentUrlMatcher = CONTENT_URL_PATTERN.matcher(url.trim()); if (!contentUrlMatcher.matches()) { throw new ContentNotFoundException(url); } int contentId = -1; int associationId = -1; int version = -1; int language = Language.NORWEGIAN_BO; String thisIdGroup = contentUrlMatcher.group("thisId"); String contentIdGroup = contentUrlMatcher.group("contentId"); String versionGroup = contentUrlMatcher.group("version"); String languageGroup = contentUrlMatcher.group("language"); String prettythisIdGroup = contentUrlMatcher.group("prettythisId"); if (thisIdGroup != null) { associationId = Integer.parseInt(thisIdGroup); } if (contentIdGroup != null) { contentId = Integer.parseInt(contentIdGroup); } if (versionGroup != null) { version = Integer.parseInt(versionGroup); } if (languageGroup != null) { language = Integer.parseInt(languageGroup); } if (prettythisIdGroup != null) { associationId = Integer.parseInt(prettythisIdGroup); } if (contentId != -1 || associationId != -1) { ContentIdentifier cid = new ContentIdentifier(); cid.setContentId(contentId); cid.setAssociationId(associationId); cid.setSiteId(siteId); cid.setVersion(version); cid.setLanguage(language); assureContentIdAndAssociationIdSet(cid); return cid; } else { url = defaultIfBlank(contentUrlMatcher.group("content"), "/"); if (siteId != -1) { if ("/".equalsIgnoreCase(url)) { Site site = siteCache.getSiteById(siteId); if (site != null) { url = site.getAlias(); } } } else if ("/".equalsIgnoreCase(url)) { Site defaultSite = siteCache.getDefaultSite(); if (defaultSite != null) { siteId = defaultSite.getId(); url = defaultSite.getAlias(); } else { siteId = 1; url = siteCache.getSiteById(siteId).getAlias(); } } else { Pair<Integer, String> urlAdjustedBySiteAlias = getUrlAdjustedBySiteAlias(null, url); siteId = urlAdjustedBySiteAlias.getLeft(); url = urlAdjustedBySiteAlias.getRight(); } return getContentIdentifier(siteId, url); } } /** * Check url for whether it starts with a site alias. If it does, remove site alias. * Eg site with alias /sitealias and url /sitealias results in url /, url /sitealias/alias gived /alias * @param site to check url against. May be null, then all sites are tested. * @param url Url to test * @return pair with siteId and adjusted url. If site given is null and no site alias match, the resulting siteId * is -1 and the same url as given is returned. */ private Pair<Integer, String> getUrlAdjustedBySiteAlias(Site site, String url) { String ajustedUrl = url.endsWith("/") ? url : url + "/"; int siteId = -1; if (site == null) { List<Site> sites = siteCache.getSites(); for (Site s : sites) { String siteAliasWithTrailingSlash = s.getAlias().endsWith("/") ? s.getAlias() : s.getAlias() + "/"; if (ajustedUrl.startsWith(siteAliasWithTrailingSlash)) { url = "/" + StringUtils.removeStart(ajustedUrl, siteAliasWithTrailingSlash); siteId = s.getId(); break; } } } else { String siteAliasWithTrailingSlash = site.getAlias().endsWith("/") ? site.getAlias() : site.getAlias() + "/"; if (ajustedUrl.startsWith(siteAliasWithTrailingSlash)) { url = "/" + StringUtils.remove(ajustedUrl, siteAliasWithTrailingSlash); } siteId = site.getId(); } return Pair.of(siteId, url); } private ContentIdentifier getContentIdentifier(int siteId, String url) throws ContentNotFoundException { ContentIdentifier cid = null; if (siteId > 0) { cid = contentIdentifierDao.getContentIdentifierBySiteIdAndAlias(siteId, url); } if (cid == null) { // we are likely in development, where no sites are configured. List<ContentIdentifier> contentIdentifiersByAlias = contentIdentifierDao .getContentIdentifiersByAlias(url); if (!contentIdentifiersByAlias.isEmpty()) { cid = contentIdentifiersByAlias.get(0); } } if (cid == null) { throw new ContentNotFoundException(url); } return cid; } private int findAssociationIdFromContentId(int contentId, int siteId, int contextId) throws SystemException { int associationId = -1; try { if (contextId != -1) { // Frst prver vi finne siden under der lenka kom fra List<Integer> associationIds = getJdbcTemplate().queryForList( "SELECT AssociationId FROM associations WHERE ContentId = ? AND Path like ? AND (IsDeleted IS NULL OR IsDeleted = 0)", Integer.class, contentId, "%/" + contextId + "/%"); if (!associationIds.isEmpty()) { associationId = associationIds.get(0); } // S i samme nettsted som lenka kom fra if (associationId == -1) { siteId = getJdbcTemplate().queryForObject( "SELECT SiteId FROM associations WHERE AssociationId = ? AND (IsDeleted IS NULL OR IsDeleted = 0)", Integer.class, contextId); } } if (associationId == -1) { List<Map<String, Object>> ids = getJdbcTemplate().queryForList( "SELECT AssociationId, SiteId FROM associations WHERE ContentId = ? AND Type = ? AND (IsDeleted IS NULL OR IsDeleted = 0)", contentId, AssociationType.DEFAULT_POSTING_FOR_SITE); for (Map<String, Object> id : ids) { int tmp = ((Number) id.get("AssociationId")).intValue(); int tmpSiteId = ((Number) id.get("SiteId")).intValue(); if (associationId == -1 || tmpSiteId == siteId) { associationId = tmp; } } } } catch (DataAccessException e) { log.error("Could not find associationId for contentid " + contentId); } return associationId; } private int findContentIdFromAssociationId(int associationId) throws SystemException { int contentId = -1; List<Pair<Integer, Integer>> contentIdAndTypes = getJdbcTemplate().query( "select ContentId, Type from associations where AssociationId = ?", associationContentIdAndTypeMapper, associationId); if (contentIdAndTypes.size() == 1) { contentId = contentIdAndTypes.get(0).getLeft(); } else if (contentIdAndTypes.size() > 1) { log.warn( "Got several results for select ContentId, Type from associations where AssociationId = {}: {}", associationId, contentIdAndTypes); for (Pair<Integer, Integer> contentIdAndType : contentIdAndTypes) { if (contentIdAndType.getRight() != AssociationType.SHORTCUT) { contentId = contentIdAndType.getLeft(); break; } } } else { log.error("Could not find contentid for associationid " + associationId); } return contentId; } private int getSiteIdFromRequest(HttpServletRequest request) throws SystemException { return getSiteIdFromRequest(request, null).getLeft(); } /** * @return pair containing found siteId and the alias tried found. * If url is siteId/alias, url is adjusted to /alias */ private Pair<Integer, String> getSiteIdFromRequest(HttpServletRequest request, String url) throws SystemException { int siteId = ServletRequestUtils.getIntParameter(request, "siteId", -1); String adjustedUrl = url; if (siteId == -1) { Content content = tryGetFromRequest(request); if (content != null) { siteId = content.getAssociation().getSiteId(); } } if (siteId == -1 && url != null) { Matcher siteIdMatcher = siteIdPattern.matcher(url); if (siteIdMatcher.matches()) { siteId = Integer.parseInt(siteIdMatcher.group("siteId")); } } if (siteId == -1 && url != null) { Matcher thisIdMatcher = thisIdPattern.matcher(url); if (thisIdMatcher.matches()) { int thisId = Integer.parseInt(thisIdMatcher.group("thisId")); siteId = AssociationAO.getAssociationById(thisId).getSiteId(); } } if (siteId == -1) { Site site = siteCache.getSiteByHostname(request.getServerName()); if (site != null) { siteId = site.getId(); } if (url != null) { Pair<Integer, String> urlAdjustedBySiteAlias = getUrlAdjustedBySiteAlias(site, url); siteId = urlAdjustedBySiteAlias.getLeft(); adjustedUrl = urlAdjustedBySiteAlias.getRight(); } } if (siteId == -1) { siteId = siteCache.getDefaultSite().getId(); } return Pair.of(siteId, adjustedUrl); } @Override public ContentIdentifier fromRequest(HttpServletRequest request) throws ContentNotFoundException { ContentIdentifier contentIdentifier = null; String url = request.getServletPath(); String path = request.getPathInfo(); Content current = tryGetFromRequest(request); if (current != null) { contentIdentifier = ContentIdentifier.fromAssociationId(current.getAssociation().getId()); contentIdentifier.setLanguage(current.getLanguage()); contentIdentifier.setVersion(current.getVersion()); } else if (request.getParameter("contentId") != null || request.getParameter("thisId") != null) { if (request.getParameter("contentId") != null) { contentIdentifier = ContentIdentifier .fromContentId(ServletRequestUtils.getIntParameter(request, "contentId", defaultContentID)); contentIdentifier.setSiteId(ServletRequestUtils.getIntParameter(request, "siteId", defaultSiteId)); contentIdentifier .setContextId(ServletRequestUtils.getIntParameter(request, "contextId", defaultContextId)); } else { try { contentIdentifier = ContentIdentifier .fromAssociationId(ServletRequestUtils.getIntParameter(request, "thisId")); } catch (ServletRequestBindingException e) { throw new ContentNotFoundException(request.getParameter("thisId")); } } contentIdentifier .setLanguage(ServletRequestUtils.getIntParameter(request, "language", Language.NORWEGIAN_BO)); } else if (url.startsWith(Aksess.CONTENT_URL_PREFIX) && path != null && path.indexOf('/') == 0) { try { int slashIndex = path.indexOf('/', 1); if (slashIndex != -1) { contentIdentifier = ContentIdentifier .fromAssociationId(Integer.parseInt(path.substring(1, slashIndex))); } } catch (NumberFormatException e) { throw new ContentNotFoundException(path); } } else { if (url.endsWith(Aksess.getStartPage())) { // Used when a directory with a index.jsp is accessed directly url = url.substring(0, url.length() - Aksess.getStartPage().length() + 1); } String queryString = request.getQueryString(); if (queryString != null && queryString.length() > 0) { url = url + "?" + queryString; } int siteId = getSiteIdFromRequest(request); contentIdentifier = findContentIdentifier(siteId, url); } if (contentIdentifier != null) { contentIdentifier.setVersion(ServletRequestUtils.getIntParameter(request, "version", defaultVersion)); } return contentIdentifier; } @Override public ContentIdentifier fromRequestAndUrl(HttpServletRequest request, String url) throws ContentNotFoundException, SystemException { Pair<Integer, String> siteId = getSiteIdFromRequest(request, url); return findContentIdentifier(siteId.getLeft(), siteId.getRight()); } @Override public ContentIdentifier fromSiteIdAndUrl(int siteId, String url) throws SystemException, ContentNotFoundException { return findContentIdentifier(siteId, url); } @Override public ContentIdentifier fromUrl(String url) throws ContentNotFoundException, SystemException { return findContentIdentifier(-1, url); } @Override public void assureContentIdAndAssociationIdSet(ContentIdentifier contentIdentifier) { if (contentIdentifier != null) { int associationId = contentIdentifier.getAssociationId(); int contentId = contentIdentifier.getContentId(); if (contentId != -1 && associationId == -1) { try { associationId = findAssociationIdFromContentId(contentId, contentIdentifier.getSiteId(), contentIdentifier.getContextId()); contentIdentifier.setAssociationId(associationId); } catch (SystemException e) { log.error("", e); } } else if (contentId == -1 && associationId != -1) { try { contentId = findContentIdFromAssociationId(associationId); contentIdentifier.setContentId(contentId); } catch (SystemException e) { log.error("", e); } } } } @Override public void assureAssociationIdSet(ContentIdentifier contentIdentifier) { if (contentIdentifier != null) { int associationId = contentIdentifier.getAssociationId(); int contentId = contentIdentifier.getContentId(); if (contentId != -1 && associationId == -1) { try { associationId = findAssociationIdFromContentId(contentId, contentIdentifier.getSiteId(), contentIdentifier.getContextId()); contentIdentifier.setAssociationId(associationId); } catch (SystemException e) { log.error("", e); } } } } @Override public void setServletContext(ServletContext servletContext) { CONTENT_URL_PATTERN = Pattern.compile( ContentPatterns.getPatternWithContextPath(servletContext.getContextPath()), Pattern.UNICODE_CHARACTER_CLASS); } private static final RowMapper<Pair<Integer, Integer>> associationContentIdAndTypeMapper = new RowMapper<Pair<Integer, Integer>>() { @Override public Pair<Integer, Integer> mapRow(ResultSet rs, int rowNum) throws SQLException { return Pair.of(rs.getInt("ContentId"), rs.getInt("Type")); } }; }