/* See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * Esri Inc. 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. */ package com.esri.gpt.catalog.harvest.repository; import com.esri.gpt.catalog.arcims.ImsServiceException; import com.esri.gpt.catalog.management.MmdEnums; import com.esri.gpt.catalog.management.MmdEnums.ApprovalStatus; import com.esri.gpt.catalog.management.MmdEnums.PublicationMethod; import com.esri.gpt.catalog.publication.PublicationRequest; import com.esri.gpt.control.webharvest.engine.Harvester; import com.esri.gpt.control.webharvest.protocol.ProtocolSerializer; import com.esri.gpt.framework.context.RequestContext; import com.esri.gpt.framework.resource.api.Native; import com.esri.gpt.framework.resource.api.Resource; import com.esri.gpt.framework.resource.api.SourceUri; import com.esri.gpt.framework.resource.common.StringUri; import com.esri.gpt.framework.security.credentials.CredentialsDeniedException; import com.esri.gpt.framework.security.identity.IdentityException; import com.esri.gpt.framework.security.identity.NotAuthorizedException; import com.esri.gpt.framework.security.identity.local.LocalDao; import com.esri.gpt.framework.security.principal.Publisher; import com.esri.gpt.framework.security.principal.User; import com.esri.gpt.framework.sql.ManagedConnection; import com.esri.gpt.framework.util.UuidUtil; import com.esri.gpt.framework.util.Val; import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Date; import java.util.logging.Level; import java.util.logging.Logger; /** * Harvest repository update request. * <p/> * Allows to store harvest repository data in the database. If the harvest * repository has no uuid defined, it will be a new hr created with new * uuid. If has, current hr will be overwriten. */ public class HrUpdateRequest extends HrRequest { // class variables ============================================================= private static final Logger LOGGER = Logger.getLogger(HrUpdateRequest.class.getCanonicalName()); // instance variables ========================================================== /** User owning harvest repositories. */ private User _owner = new User(); /** Repository to update. */ private HrRecord _repository = new HrRecord(); // constructors ================================================================ /** * Create instance of the request. * @param requestContext request context * @param owner owner of the records * @param record record to update */ public HrUpdateRequest(RequestContext requestContext, User owner, HrRecord record) { super(requestContext, new HrCriteria(), new HrResult()); _owner = owner != null ? owner : new User(); _repository = record != null ? record : new HrRecord(); } // properties ================================================================== /** * Gets owner. * @return owner of the repository */ public User getOwner() { return _owner; } /** * Sets owner. * * <p/> * If the <code>owner</code> argument is <code>null</code> than the owner of * repositories is set to non existing user. * * @param owner owner of the repository */ public void setOwner(User owner) { _owner = owner != null ? owner : new User(); } /** * Gets repository to update. * @return repository to update */ public HrRecord getRepository() { return _repository; } /** * Sets repository to update. * @param repository repository to update */ public void setRepository(HrRecord repository) { _repository = repository != null ? repository : new HrRecord(); } // methods ===================================================================== /** * Executes request. * If native resource not provided, no metadata will be created for the repository. * @param nativeResource native resource or <code>null</code> * @throws Exception if request execution fails */ public void executeUpdate(Native nativeResource) throws Exception { Connection con = null; boolean autoCommit = true; // intitalize PreparedStatement st = null; try { HrRecord hr = getRepository(); // establish the connection ManagedConnection mc = returnConnection(); con = mc.getJdbcConnection(); autoCommit = con.getAutoCommit(); con.setAutoCommit(false); String sql = ""; boolean isUpdate = false; String sUuid = ""; boolean finableBeforeUpdate = false; if (UuidUtil.isUuid(hr.getUuid())) { sUuid = hr.getUuid(); finableBeforeUpdate = queryFindable(con); sql = createUpdateSQL(); st = con.prepareStatement(sql); isUpdate = true; } else { sUuid = UuidUtil.makeUuid(true); finableBeforeUpdate = hr.getFindable(); sql = createInsertSQL(); st = con.prepareStatement(sql); } if (hr.getOwnerId()<0) { hr.setOwnerId(getOwner().getLocalID()); } int n = 1; st.setInt(n++, hr.getOwnerId()); st.setTimestamp(n++, makeTimestamp(hr.getInputDate())); st.setTimestamp(n++, makeTimestamp(hr.getUpdateDate())); st.setString(n++, hr.getName()); st.setString(n++, hr.getHostUrl()); st.setString(n++, hr.getHarvestFrequency().toString()); st.setString(n++, Boolean.toString(hr.getSendNotification())); st.setString(n++, hr.getProtocol().getKind().toLowerCase()); st.setString(n++, ProtocolSerializer.toXmlString(hr.getProtocol())); st.setString(n++, PublicationMethod.registration.name()); if (!isUpdate) { if (getRequestContext().getApplicationConfiguration().getHarvesterConfiguration().getResourceAutoApprove()) { st.setString(n++, ApprovalStatus.approved.name()); } else { st.setString(n++, ApprovalStatus.posted.name()); } } // NOTE! Don't update 'findable' here. It has to be updated by ImsMetadataAdminDao.updateRecord. st.setString(n++, Boolean.toString(hr.getSearchable())); st.setString(n++, Boolean.toString(hr.getSynchronizable())); st.setString(n++, sUuid); logExpression(sql); int nRowCount = st.executeUpdate(); getActionResult().setNumberOfRecordsModified(nRowCount); if (!isUpdate && nRowCount==1) { closeStatement(st); st = con.prepareStatement("SELECT ID FROM "+getHarvestingTableName()+" WHERE UPPER(DOCUUID)=?"); st.setString(1, sUuid.toUpperCase()); ResultSet genKeys = st.executeQuery(); genKeys.next(); int nLocalId = genKeys.getInt(1); hr.setLocalId(nLocalId); hr.setUuid(sUuid); closeResultSet(genKeys); } con.commit(); // Use PublicationRequest if native resource present or 'findable' flag has changed. if (nativeResource!=null || (isUpdate && finableBeforeUpdate!=hr.getFindable())) { try { // If no native resource provided but this is update, fetch native resource for that // repository from database if (nativeResource==null && isUpdate) { nativeResource = queryNative(con); } // skip if still no native resource if (nativeResource!=null) { String content = nativeResource.getContent(); String sourceUri = nativeResource.getSourceUri().asString(); Publisher publisher = createPublisherOfRepository(); PublicationRequest publicationRequest = createPublicationRequest(publisher, content, sourceUri); publicationRequest.publish(); } } catch (Exception ex) { LOGGER.log(Level.INFO, "Unable to create resource definition.", ex); } } // NEW in 10.0; notify update Harvester harvestEngine = getRequestContext().getApplicationContext().getHarvestingEngine(); if (_repository.getIsHarvestDue()) { harvestEngine.submit(getRequestContext(), _repository, null, _repository.getLastSyncDate()); } harvestEngine.reselect(); } catch (Exception ex) { if (con!=null) { con.rollback(); } throw ex; } finally { closeStatement(st); if (con!=null) { con.setAutoCommit(autoCommit); } } } /** * Queries native resource. * @param con database connection * @return native connection * @throws SQLException if accessing database fails */ private Native queryNative(Connection con) throws SQLException { final String content = queryContent(con); final String sourceUri = querySourceUri(con); final Date updateDate = queryUpdateDate(con); return new Native() { @Override public SourceUri getSourceUri() { return new StringUri(sourceUri); } @Override public String getContent() throws IOException { return content; } @Override public Iterable<Resource> getNodes() { return new ArrayList<Resource>(); } @Override public Date getUpdateDate() { return updateDate; } }; } /** * Queries content. * @param con database content * @return content * @throws SQLException if accessing database fails */ private String queryContent(Connection con) throws SQLException { String xml = ""; StringBuilder sbSql = new StringBuilder(); sbSql.append("SELECT XML FROM ").append(getHarvestingDataTableName()).append(" "); sbSql.append("WHERE DOCUUID=?"); PreparedStatement st = null; ResultSet rs = null; try { st = con.prepareStatement(sbSql.toString()); st.setString(1, getRepository().getUuid()); logExpression(sbSql.toString()); rs = st.executeQuery(); if (rs.next()) { xml = Val.chkStr(rs.getString(1)); } } finally { closeResultSet(rs); closeStatement(st); } return xml; } /** * Queries source URI. * @param con database connection * @return source URI * @throws SQLException if accessing database fails */ private String querySourceUri(Connection con) throws SQLException { String sourceUri = ""; StringBuilder sbSql = new StringBuilder(); sbSql.append("SELECT SOURCEURI FROM ").append(getHarvestingTableName()).append(" "); sbSql.append("WHERE DOCUUID=?"); PreparedStatement st = null; ResultSet rs = null; try { st = con.prepareStatement(sbSql.toString()); st.setString(1, getRepository().getUuid()); logExpression(sbSql.toString()); rs = st.executeQuery(); if (rs.next()) { sourceUri = Val.chkStr(rs.getString(1)); } } finally { closeResultSet(rs); closeStatement(st); } return sourceUri; } /** * Queries update date. * @param con database connection * @return source URI * @throws SQLException if accessing database fails */ private Date queryUpdateDate(Connection con) throws SQLException { Date updateDate = null; StringBuilder sbSql = new StringBuilder(); sbSql.append("SELECT UPDATEDATE FROM ").append(getHarvestingTableName()).append(" "); sbSql.append("WHERE DOCUUID=?"); PreparedStatement st = null; ResultSet rs = null; try { st = con.prepareStatement(sbSql.toString()); st.setString(1, getRepository().getUuid()); logExpression(sbSql.toString()); rs = st.executeQuery(); if (rs.next()) { updateDate = rs.getTimestamp(1); } } finally { closeResultSet(rs); closeStatement(st); } return updateDate; } /** * Creates publication request. * @param publisher publisher * @param content content * @param xml source URI * @return request */ private PublicationRequest createPublicationRequest(Publisher publisher, String content, String sourceUri) { PublicationRequest publicationRequest = new PublicationRequest(getRequestContext(), publisher, content); publicationRequest.getPublicationRecord().setUuid(getRepository().getUuid()); publicationRequest.getPublicationRecord().setPublicationMethod(MmdEnums.PublicationMethod.registration.toString()); publicationRequest.getPublicationRecord().setSourceUri(sourceUri); publicationRequest.getPublicationRecord().setSourceFileName(sourceUri); publicationRequest.getPublicationRecord().setAutoApprove(getRequestContext().getApplicationConfiguration().getHarvesterConfiguration().getResourceAutoApprove()); publicationRequest.getPublicationRecord().setAlternativeTitle(getRepository().getName()); publicationRequest.getPublicationRecord().setUpdateOnlyIfXmlHasChanged(false); publicationRequest.getPublicationRecord().setIndexEnabled(getRepository().getFindable()); return publicationRequest; } /** * Creates publisher of the repository. * @return publisher * @throws SQLException if accessing database fails * @throws CredentialsDeniedException if invalid credentials * @throws NotAuthorizedException if not authorized * @throws IdentityException if no identity found * @throws ImsServiceException if accessing ArcIMS service fails */ private Publisher createPublisherOfRepository() throws SQLException, CredentialsDeniedException, NotAuthorizedException, IdentityException, ImsServiceException { LocalDao localDao = new LocalDao(getRequestContext()); String uDN = localDao.readDN(getRepository().getOwnerId()); Publisher publisher = new Publisher(getRequestContext(), uDN); return publisher; } /** * Queries findable. * @param con database connection * @return findable * @throws SQLException if accessing database fails */ private boolean queryFindable(Connection con) throws SQLException { boolean findable = false; StringBuilder sbSql = new StringBuilder(); sbSql.append("SELECT FINDABLE FROM ").append(getHarvestingTableName()).append(" "); sbSql.append("WHERE DOCUUID=?"); PreparedStatement st = null; ResultSet rs = null; try { st = con.prepareStatement(sbSql.toString()); st.setString(1, getRepository().getUuid()); logExpression(sbSql.toString()); rs = st.executeQuery(); if (rs.next()) { findable = Val.chkBool(rs.getString(1), false); } } finally { closeResultSet(rs); closeStatement(st); } return findable; } /** * Creates INSERT SQL. * @return INSERT SQL */ private String createInsertSQL() { StringBuilder sbInsertSql = new StringBuilder(); // NOTE! Don't update 'findable' here. It has to be updated by ImsMetadataAdminDao.updateRecord. sbInsertSql.append("insert into ").append(getHarvestingTableName()).append(" "); sbInsertSql.append("(OWNER,INPUTDATE,UPDATEDATE,TITLE,"); sbInsertSql.append("HOST_URL,FREQUENCY,"); sbInsertSql.append("SEND_NOTIFICATION,PROTOCOL_TYPE,PROTOCOL,PUBMETHOD,APPROVALSTATUS,"); sbInsertSql.append("SEARCHABLE,SYNCHRONIZABLE,"); sbInsertSql.append("DOCUUID)"); sbInsertSql.append("values (?,?,?,?,?,?,?,?,?,?,?,?,?,?)"); return sbInsertSql.toString(); } /** * Creates UPDATE SQL. * @return UPDATE SQL */ private String createUpdateSQL() { StringBuilder sbUpdateSql = new StringBuilder(); // NOTE! Don't update 'findable' here. It has to be updated by ImsMetadataAdminDao.updateRecord. sbUpdateSql.append("update ").append(getHarvestingTableName()).append(" "); sbUpdateSql.append("set OWNER=?,INPUTDATE=?,UPDATEDATE=?,"); sbUpdateSql.append("TITLE=?,HOST_URL=?,FREQUENCY=?,"); sbUpdateSql.append("SEND_NOTIFICATION=?,PROTOCOL_TYPE=?,PROTOCOL=?,PUBMETHOD=?, "); sbUpdateSql.append("SEARCHABLE=?,SYNCHRONIZABLE=? "); sbUpdateSql.append("where DOCUUID=?"); return sbUpdateSql.toString(); } /** * Creates timestamp from date. * If date is <code>null</code>, timestamp will be <code>null</code> as well. * @param date date to make timestamp * @return timestamp */ private java.sql.Timestamp makeTimestamp(Date date) { return date != null ? new java.sql.Timestamp(date.getTime()) : null; } }