/* * Copyright 2011 FatWire Corporation. All Rights Reserved. * * 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 tools.gsf.mapping; import COM.FutureTense.Interfaces.ICS; import COM.FutureTense.Interfaces.Utilities; import com.fatwire.cs.core.db.PreparedStmt; import com.fatwire.cs.core.db.StatementParam; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import tools.gsf.facade.assetapi.AssetAccessTemplate; import tools.gsf.facade.assetapi.AssetIdWithSite; import tools.gsf.facade.sql.Row; import tools.gsf.facade.sql.SqlHelper; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Map; /** * MappingService implementation making use to sql queries to perform fast lookup of mapping values. * * @author Dolf Dijkstra * @author Tony Field * @since Apr 13, 2011 */ public final class IcsMappingService implements MappingService { private static final Logger LOG = LoggerFactory.getLogger(IcsMappingService.class); private final static PreparedStmt template = new PreparedStmt("SELECT * FROM Template_Map WHERE cs_ownerid=? AND cs_siteid=?", Arrays.asList("Template", "Template_Map")); private final static PreparedStmt element = new PreparedStmt("SELECT * FROM CSElement_Map WHERE cs_ownerid=? AND cs_siteid=?", Arrays.asList("CSElement", "CSElement_Map")); private static final PreparedStmt lookup_sitecatalog = new PreparedStmt("select * from SiteCatalog where pagename = ?", Arrays.asList("SiteEntry","Template")); // we will only query pagenames that map to these, we promise... we use SiteEntry and Template instead of SiteCatalog to avoid security blocking the query private static final PreparedStmt lookup_template = new PreparedStmt("select * from Template where rootelement = ?", Collections.singletonList("Template")); // we will only query pagenames that map to these, we promise private static final PreparedStmt lookup_cselement = new PreparedStmt("select * from CSElement where rootelement = ?", Collections.singletonList("CSElement")); // we will only query pagenames that map to these, we promise static { template.setElement(0, "Template_Map", "cs_ownerid"); template.setElement(1, "Template_Map", "cs_siteid"); element.setElement(0, "CSElement_Map", "cs_ownerid"); element.setElement(1, "CSElement_Map", "cs_siteid"); lookup_sitecatalog.setElement(0, "SiteEntry", "pagename"); // Using SiteEntry instead of SiteCatalog so to avoid security blocking the query lookup_template.setElement(0, "Template", "rootelement"); lookup_cselement.setElement(0, "CSElement", "rootelement"); } private final ICS ics; private final AssetAccessTemplate aat; /** * @param ics Content Server context object * @param aat AssetAccessTemplate object */ public IcsMappingService(final ICS ics, final AssetAccessTemplate aat) { this.ics = ics; this.aat = aat; } public Map<String, MappingValue> readMapping(final AssetIdWithSite id) { if ("Template".equals(id.getType())) { return readIt(id, template); } else if ("CSElement".equals(id.getType())) { return readIt(id, element); } else { throw new IllegalArgumentException("Cannot handle " + id.getType()); } } private Map<String, MappingValue> readIt(final AssetIdWithSite id, final PreparedStmt stmt) { final StatementParam param = stmt.newParam(); param.setLong(0, id.getId()); param.setLong(1, aat.readSiteInfo(id.getSite()).getId()); final Map<String, MappingValue> map = new HashMap<>(); for (final Row row : SqlHelper.select(ics, stmt, param)) { final String key = row.getString("cs_key"); final MappingValue k = new MappingValue(MappingValue.Type.valueOf(row.getString("cs_type").toLowerCase()), row.getString("cs_value")); map.put(key, k); } return map; } @Override public AssetIdWithSite resolveMapped(String eid, String tid, String site) { if (site != null) { if (eid != null) { return new AssetIdWithSite("CSElement", Long.valueOf(eid), site); } if (tid != null) { return new AssetIdWithSite("Template", Long.valueOf(tid), site); } } return null; } @Override public AssetIdWithSite resolveMapped(String pagename) { // note: we can only map templates or CSElements that are rootelements of pages. We cannot resolve // the mapped code in other cases unfortunately. MappingPageData pageData = readPageData(pagename); if (pageData.isSiteEntry()) { LOG.debug("PageData is SiteEntry"); long eid = lookupCSElement(pageData.rootelement); if (LOG.isDebugEnabled()) { LOG.debug("Looked up eid for rootelement '" + pageData.rootelement + "', got: " + eid); } if (eid > -1) { String site = ics.GetVar("site"); LOG.debug("site = " + site); if (StringUtils.isBlank(site)) { LOG.debug("Cannot find site... will attempt extracting it from resargs"); site = pageData.getSiteResarg(); LOG.debug("site = " + site); } if (StringUtils.isNotBlank(site)) { return new AssetIdWithSite("CSElement", eid, site); } } } else { LOG.debug("PageData not a SiteEntry... assuming Template"); long tid = lookupTemplate(pageData.rootelement); if (LOG.isDebugEnabled()) { LOG.debug("Looked up tid for rootelement '" + pageData.rootelement + "', got: " + tid); } if (tid > 0) { String site = ics.GetVar("site"); LOG.debug("site = " + site); if (StringUtils.isBlank(site)) { if (LOG.isDebugEnabled()) { LOG.debug("Will look up site for (pressumed) template..."); } site = lookupSiteForTemplate(pageData); LOG.debug("site = " + site); } if (StringUtils.isNotBlank(site)) { return new AssetIdWithSite("Template", tid, site); } } } LOG.debug("Cannot determine asset ID (CSElement eid / Template tid) from pagename '" + pagename + "'"); return null; } private MappingPageData readPageData(String pagename) { StatementParam param = lookup_sitecatalog.newParam(); param.setString(0, pagename); Row row = SqlHelper.selectSingle(ics, lookup_sitecatalog, param); return new MappingPageData(row); } private long lookupCSElement(String rootelement) { StatementParam param = lookup_cselement.newParam(); param.setString(0, rootelement); Row row = SqlHelper.selectSingle(ics, lookup_cselement, param); return row == null ? -1L : row.getLong("id"); } private long lookupTemplate(String rootelement) { StatementParam param = lookup_template.newParam(); param.setString(0, rootelement); Row row = SqlHelper.selectSingle(ics, lookup_template, param); return row == null ? -1L : row.getLong("id"); } private String lookupSiteForTemplate(MappingPageData pageData) { // always siteName/type/tname or siteName/tname return StringUtils.substringBefore(pageData.pagename, "/"); } private static class MappingPageData { private final String pagename; private final Map<String,String> resargs; private final String rootelement; // could add more here if we cared but this is a private class so no need to worry now private MappingPageData(Row row) { this.pagename = row.getString("pagename"); this.resargs = new HashMap<>(); Utilities.getParams(row.getString("resargs1"), resargs, false); Utilities.getParams(row.getString("resargs2"), resargs, false); this.rootelement = row.getString("rootelement"); } private boolean isSiteEntry() { return resargs.containsKey("seid"); } private String getSiteResarg() { return resargs.get("site"); } } }