diff --git a/config/alfresco/patch/extended-patches-context.xml b/config/alfresco/patch/extended-patches-context.xml new file mode 100644 index 0000000000..a690d9fef9 --- /dev/null +++ b/config/alfresco/patch/extended-patches-context.xml @@ -0,0 +1,17 @@ + + + + + + + + + + Dummy + A dummy patch + 0 + + + diff --git a/source/java/org/alfresco/repo/admin/patch/PatchDaoService.java b/source/java/org/alfresco/repo/admin/patch/PatchDaoService.java index a280753f0a..39ca5437b5 100644 --- a/source/java/org/alfresco/repo/admin/patch/PatchDaoService.java +++ b/source/java/org/alfresco/repo/admin/patch/PatchDaoService.java @@ -16,6 +16,7 @@ */ package org.alfresco.repo.admin.patch; +import java.util.Date; import java.util.List; import org.alfresco.repo.domain.AppliedPatch; @@ -45,10 +46,29 @@ public interface PatchDaoService */ public AppliedPatch getAppliedPatch(String id); + /** + * Detaches the given instance from the persistence engine. This will + * ensure that any changes made to the java object do not get persisted, + * allowing the objects to be passed out to external clients without any + * concern of their lifecycle. + * + * @param appliedPatch the object to detach from persistence + */ + public void detach(AppliedPatch appliedPatch); + /** * Get a list of all applied patches * * @return Returns a list of all applied patches */ public List getAppliedPatches(); + + /** + * Get a list of all patches applied between the given dates + * + * @param from the lower date limit or null to ignore + * @param to the upper date limit or null to ignore + * @return Returns all applied patches + */ + public List getAppliedPatches(Date from, Date to); } diff --git a/source/java/org/alfresco/repo/admin/patch/PatchExecuter.java b/source/java/org/alfresco/repo/admin/patch/PatchExecuter.java index a07bddd725..86500ad570 100644 --- a/source/java/org/alfresco/repo/admin/patch/PatchExecuter.java +++ b/source/java/org/alfresco/repo/admin/patch/PatchExecuter.java @@ -16,6 +16,10 @@ */ package org.alfresco.repo.admin.patch; +import java.util.Date; +import java.util.List; + +import org.alfresco.error.AlfrescoRuntimeException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -42,20 +46,48 @@ public class PatchExecuter /** * Ensures that all outstanding patches are applied. */ - public void applyOutStandingPatches() + public void applyOutstandingPatches() { - /* - * TODO: This is simplistic at the moment. It must do better reporting of failures. - */ + Date before = new Date(System.currentTimeMillis() - 20000L); // 20 seconds ago + patchService.applyOutstandingPatches(); + Date after = new Date(System .currentTimeMillis() + 20000L); // 20 seconds ahead - boolean success = patchService.applyOutstandingPatches(); - if (!success) + // get all the patches executed in the time + List appliedPatches = patchService.getPatches(before, after); + + // don't report anything if nothing was done + if (appliedPatches.size() == 0) { - logger.error("Not all patches could be applied"); + if (logger.isDebugEnabled()) + { + logger.debug("No patches applied"); + } } else { - logger.info("Patches applied successfully"); + boolean succeeded = true; + // list all patches applied, including failures + for (PatchInfo patchInfo : appliedPatches) + { + if (patchInfo.getSucceeded()) + { + logger.info("Applied patch: \n" + + " ID: " + patchInfo.getId() + "\n" + + " RESULT: " + patchInfo.getReport()); + } + else + { + succeeded = false; + logger.error("Failed to apply patch: \n" + + " ID: " + patchInfo.getId() + "\n" + + " RESULT: " + patchInfo.getReport()); + } + } + // generate an error if there was a failure + if (!succeeded) + { + throw new AlfrescoRuntimeException("Not all patches could be applied"); + } } } } diff --git a/source/java/org/alfresco/repo/admin/patch/PatchInfo.java b/source/java/org/alfresco/repo/admin/patch/PatchInfo.java new file mode 100644 index 0000000000..b05072bae4 --- /dev/null +++ b/source/java/org/alfresco/repo/admin/patch/PatchInfo.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * 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 org.alfresco.repo.admin.patch; + +import java.util.Date; + +/** + * Data on applied patches + * + * @author Derek Hulley + */ +public interface PatchInfo +{ + public String getId(); + + public String getDescription(); + + public int getFixesFromSchema(); + + public int getFixesToSchema(); + + public int getTargetSchema(); + + public int getAppliedToSchema(); + + public String getAppliedToServer(); + + public Date getAppliedOnDate(); + + public boolean getSucceeded(); + + public String getReport(); +} diff --git a/source/java/org/alfresco/repo/admin/patch/PatchService.java b/source/java/org/alfresco/repo/admin/patch/PatchService.java index 59f3e5e90e..a9691dc038 100644 --- a/source/java/org/alfresco/repo/admin/patch/PatchService.java +++ b/source/java/org/alfresco/repo/admin/patch/PatchService.java @@ -16,6 +16,9 @@ */ package org.alfresco.repo.admin.patch; +import java.util.Date; +import java.util.List; + /** * Manages patches applied against the repository. *

@@ -43,4 +46,13 @@ public interface PatchService * was termintated before all patches could be applied. */ public boolean applyOutstandingPatches(); + + /** + * Retrieves all applied patches between two specific times. + * + * @param from the start date of the search, or null to get all patches from the start + * @param to the end date of the search, or null to g + * @return Returns all applied patches (successful or not) + */ + public List getPatches(Date fromDate, Date toDate); } diff --git a/source/java/org/alfresco/repo/admin/patch/PatchServiceImpl.java b/source/java/org/alfresco/repo/admin/patch/PatchServiceImpl.java index 9d87134f1e..309a0c052c 100644 --- a/source/java/org/alfresco/repo/admin/patch/PatchServiceImpl.java +++ b/source/java/org/alfresco/repo/admin/patch/PatchServiceImpl.java @@ -41,6 +41,9 @@ import org.apache.commons.logging.LogFactory; */ public class PatchServiceImpl implements PatchService { + private static final Date ZERO_DATE = new Date(0L); + private static final Date INFINITE_DATE = new Date(Long.MAX_VALUE); + private static Log logger = LogFactory.getLog(PatchServiceImpl.class); private DescriptorService descriptorService; @@ -169,7 +172,7 @@ public class PatchServiceImpl implements PatchService { // create a dummy report StringBuilder sb = new StringBuilder(128); - sb.append("Patch ").append(patch.getId()).append(" was not relevant."); + sb.append("Not relevant to schema " + repoDescriptor.getSchema()); report = sb.toString(); success = true; // this succeeded because it didn't need to be applied } @@ -192,8 +195,11 @@ public class PatchServiceImpl implements PatchService Descriptor serverDescriptor = descriptorService.getServerDescriptor(); String server = (serverDescriptor.getVersion() + " - " + serverDescriptor.getEdition()); - // create a record for the execution - appliedPatch = patchDaoService.newAppliedPatch(patch.getId()); + // create or update the record of execution + if (appliedPatch == null) + { + appliedPatch = patchDaoService.newAppliedPatch(patch.getId()); + } // fill in the record's details appliedPatch.setDescription(patch.getDescription()); appliedPatch.setFixesFromSchema(patch.getFixesFromSchema()); @@ -235,4 +241,25 @@ public class PatchServiceImpl implements PatchService } return apply; } + + @SuppressWarnings("unchecked") + public List getPatches(Date fromDate, Date toDate) + { + if (fromDate == null) + { + fromDate = ZERO_DATE; + } + if (toDate == null) + { + toDate = INFINITE_DATE; + } + List appliedPatches = patchDaoService.getAppliedPatches(fromDate, toDate); + // disconnect each of these + for (PatchInfo appliedPatch : appliedPatches) + { + patchDaoService.detach((AppliedPatch)appliedPatch); + } + // done + return (List) appliedPatches; + } } diff --git a/source/java/org/alfresco/repo/admin/patch/PatchTest.java b/source/java/org/alfresco/repo/admin/patch/PatchTest.java index b3779636e1..cc5be82af8 100644 --- a/source/java/org/alfresco/repo/admin/patch/PatchTest.java +++ b/source/java/org/alfresco/repo/admin/patch/PatchTest.java @@ -16,6 +16,7 @@ */ package org.alfresco.repo.admin.patch; +import java.util.Date; import java.util.List; import junit.framework.TestCase; @@ -138,4 +139,28 @@ public class PatchTest extends TestCase assertTrue("Sample 01 not in list of applied patches", found01); assertTrue("Sample 02 not in list of applied patches", found02); } + + public void testGetPatchesByDate() throws Exception + { + // ensure that there are some applied patches + testApplyOutstandingPatches(); + // get the number of applied patches + List appliedPatches = patchDaoComponent.getAppliedPatches(); + assertTrue("Expected at least 2 applied patches", appliedPatches.size() >= 2); + + // now requery using null dates + List appliedPatchesAllDates = patchService.getPatches(null, null); + assertEquals("Applied patches by all dates doesn't match all applied patches", + appliedPatches.size(), appliedPatchesAllDates.size()); + + // make sure that the objects are not connected to the persistence layer + PatchInfo disconnectedObject = appliedPatchesAllDates.get(0); + AppliedPatch persistedObject = patchDaoComponent.getAppliedPatch(disconnectedObject.getId()); + assertNotSame("Instances should not be shared between evicted and cached objects", + disconnectedObject, persistedObject); + + // perform another query with dates that should return no results + List appliedPatchesFutureDates = patchService.getPatches(new Date(), new Date()); + assertEquals("Query returned results for dates when no patches should exist", 0, appliedPatchesFutureDates.size()); + } } diff --git a/source/java/org/alfresco/repo/admin/patch/hibernate/HibernatePatchDaoServiceImpl.java b/source/java/org/alfresco/repo/admin/patch/hibernate/HibernatePatchDaoServiceImpl.java index bf560bdd72..86c46e9bcf 100644 --- a/source/java/org/alfresco/repo/admin/patch/hibernate/HibernatePatchDaoServiceImpl.java +++ b/source/java/org/alfresco/repo/admin/patch/hibernate/HibernatePatchDaoServiceImpl.java @@ -16,6 +16,8 @@ */ package org.alfresco.repo.admin.patch.hibernate; +import java.util.Date; +import java.util.Iterator; import java.util.List; import org.alfresco.error.AlfrescoRuntimeException; @@ -36,6 +38,7 @@ import org.springframework.orm.hibernate3.support.HibernateDaoSupport; public class HibernatePatchDaoServiceImpl extends HibernateDaoSupport implements PatchDaoService { public static final String QUERY_GET_ALL_APPLIED_PATCHES = "patch.GetAllAppliedPatches"; + public static final String QUERY_GET_APPLIED_PATCHES_BY_DATE = "patch.GetAppliedPatchesByDate"; public AppliedPatch newAppliedPatch(String id) { @@ -62,6 +65,11 @@ public class HibernatePatchDaoServiceImpl extends HibernateDaoSupport implements return patch; } + public void detach(AppliedPatch appliedPatch) + { + getSession().evict(appliedPatch); + } + /** * @see #QUERY_GET_ALL_APPLIED_PATCHES */ @@ -80,4 +88,35 @@ public class HibernatePatchDaoServiceImpl extends HibernateDaoSupport implements // done return queryResults; } + + /** + * @see #QUERY_GET_APPLIED_PATCHES_BY_DATE + */ + @SuppressWarnings("unchecked") + public List getAppliedPatches(final Date fromDate, final Date toDate) + { + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session.getNamedQuery(HibernatePatchDaoServiceImpl.QUERY_GET_ALL_APPLIED_PATCHES); + return query.list(); + } + }; + List queryResults = (List) getHibernateTemplate().execute(callback); + // eliminate results that are out of range + Iterator iterator = queryResults.iterator(); + while (iterator.hasNext()) + { + AppliedPatch appliedPatch = iterator.next(); + Date appliedOnDate = appliedPatch.getAppliedOnDate(); + if (fromDate.compareTo(appliedOnDate) >= 0 || toDate.compareTo(appliedOnDate) <= 0) + { + // it is out of range + iterator.remove(); + } + } + // done + return queryResults; + } } diff --git a/source/java/org/alfresco/repo/domain/AppliedPatch.java b/source/java/org/alfresco/repo/domain/AppliedPatch.java index a65623a97e..f114a9b762 100644 --- a/source/java/org/alfresco/repo/domain/AppliedPatch.java +++ b/source/java/org/alfresco/repo/domain/AppliedPatch.java @@ -18,40 +18,32 @@ package org.alfresco.repo.domain; import java.util.Date; +import org.alfresco.repo.admin.patch.PatchInfo; + /** * Interface for persistent patch application information. * * @author Derek Hulley */ -public interface AppliedPatch +public interface AppliedPatch extends PatchInfo { - public String getId(); public void setId(String id); - public String getDescription(); public void setDescription(String description); - public int getFixesFromSchema(); public void setFixesFromSchema(int version); - public int getFixesToSchema(); public void setFixesToSchema(int version); - public int getTargetSchema(); public void setTargetSchema(int version); - public int getAppliedToSchema(); public void setAppliedToSchema(int version); - public String getAppliedToServer(); public void setAppliedToServer(String server); - public Date getAppliedOnDate(); public void setAppliedOnDate(Date date); - public boolean getSucceeded(); public void setSucceeded(boolean succeeded); - public String getReport(); public void setReport(String report); } diff --git a/source/java/org/alfresco/repo/domain/hibernate/AppliedPatch.hbm.xml b/source/java/org/alfresco/repo/domain/hibernate/AppliedPatch.hbm.xml index c18a655168..b3f4836508 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/AppliedPatch.hbm.xml +++ b/source/java/org/alfresco/repo/domain/hibernate/AppliedPatch.hbm.xml @@ -33,4 +33,16 @@ org.alfresco.repo.domain.hibernate.AppliedPatchImpl as appliedPatch + + = :fromDate and + appliedPatch.appliedOnDate <= :toDate + ]]> + +