KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > alfresco > repo > admin > patch > PatchServiceImpl


1 /*
2  * Copyright (C) 2005 Alfresco, Inc.
3  *
4  * Licensed under the Mozilla Public License version 1.1
5  * with a permitted attribution clause. You may obtain a
6  * copy of the License at
7  *
8  * http://www.alfresco.org/legal/license.txt
9  *
10  * Unless required by applicable law or agreed to in writing,
11  * software distributed under the License is distributed on an
12  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific
14  * language governing permissions and limitations under the
15  * License.
16  */

17 package org.alfresco.repo.admin.patch;
18
19 import java.util.ArrayList JavaDoc;
20 import java.util.Date JavaDoc;
21 import java.util.HashMap JavaDoc;
22 import java.util.List JavaDoc;
23 import java.util.Map JavaDoc;
24
25 import org.alfresco.i18n.I18NUtil;
26 import org.alfresco.repo.domain.AppliedPatch;
27 import org.alfresco.service.cmr.admin.PatchException;
28 import org.alfresco.service.descriptor.Descriptor;
29 import org.alfresco.service.descriptor.DescriptorService;
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32
33
34 /**
35  * Manages patches applied against the repository.
36  * <p>
37  * Patches are injected into this class and any attempted applications are recorded
38  * for later auditing.
39  *
40  * @since 1.2
41  * @author Derek Hulley
42  */

43 public class PatchServiceImpl implements PatchService
44 {
45     private static final String JavaDoc MSG_NOT_RELEVANT = "patch.service.not_relevant";
46     
47     private static final Date JavaDoc ZERO_DATE = new Date JavaDoc(0L);
48     private static final Date JavaDoc INFINITE_DATE = new Date JavaDoc(Long.MAX_VALUE);
49     
50     private static Log logger = LogFactory.getLog(PatchServiceImpl.class);
51     
52     private DescriptorService descriptorService;
53     private PatchDaoService patchDaoService;
54     private List JavaDoc<Patch> patches;
55
56     public PatchServiceImpl()
57     {
58         this.patches = new ArrayList JavaDoc<Patch>(10);
59     }
60     
61     public void setDescriptorService(DescriptorService descriptorService)
62     {
63         this.descriptorService = descriptorService;
64     }
65
66     public void setPatchDaoService(PatchDaoService patchDaoService)
67     {
68         this.patchDaoService = patchDaoService;
69     }
70
71     public void registerPatch(Patch patch)
72     {
73         patches.add(patch);
74     }
75
76     public boolean applyOutstandingPatches()
77     {
78         // construct a map of all known patches by ID
79
Map JavaDoc<String JavaDoc, Patch> allPatchesById = new HashMap JavaDoc<String JavaDoc, Patch>(23);
80         for (Patch patch : patches)
81         {
82             allPatchesById.put(patch.getId(), patch);
83         }
84         // construct a list of executed patches by ID
85
Map JavaDoc<String JavaDoc, AppliedPatch> appliedPatchesById = new HashMap JavaDoc<String JavaDoc, AppliedPatch>(23);
86         List JavaDoc<AppliedPatch> appliedPatches = patchDaoService.getAppliedPatches();
87         for (AppliedPatch appliedPatch : appliedPatches)
88         {
89             appliedPatchesById.put(appliedPatch.getId(), appliedPatch);
90         }
91         // go through all the patches and apply them where necessary
92
boolean success = true;
93         for (Patch patch : allPatchesById.values())
94         {
95             // apply the patch
96
success = applyPatchAndDependencies(patch, appliedPatchesById);
97             if (!success)
98             {
99                 // we failed to apply a patch or one of its dependencies - terminate
100
break;
101             }
102         }
103         // done
104
return success;
105     }
106     
107     /**
108      * Reentrant method that ensures that a patch and all its dependencies get applied.
109      * The process terminates on the first failure.
110      *
111      * @param patchInfos all the executed patch data. If there was a failure, then this
112      * is the list of successful executions only.
113      * @param patch the patch (containing dependencies) to apply
114      * @param appliedPatchesById already applied patches keyed by their ID
115      * @return Returns true if the patch and all its dependencies were successfully applied.
116      */

117     private boolean applyPatchAndDependencies(Patch patch, Map JavaDoc<String JavaDoc, AppliedPatch> appliedPatchesById)
118     {
119         String JavaDoc id = patch.getId();
120         // check if it has already been done
121
AppliedPatch appliedPatch = appliedPatchesById.get(id);
122         if (appliedPatch != null && appliedPatch.getSucceeded())
123         {
124             // this has already been done
125
return true;
126         }
127         
128         // ensure that dependencies have been done
129
List JavaDoc<Patch> dependencies = patch.getDependsOn();
130         for (Patch dependencyPatch : dependencies)
131         {
132             boolean success = applyPatchAndDependencies(dependencyPatch, appliedPatchesById);
133             if (!success)
134             {
135                 // a patch failed to be applied
136
return false;
137             }
138         }
139         // all the dependencies were successful
140
appliedPatch = applyPatch(patch);
141         if (!appliedPatch.getSucceeded())
142         {
143             // this was a failure
144
return false;
145         }
146         else
147         {
148             // it was successful - add it to the map of successful patches
149
appliedPatchesById.put(id, appliedPatch);
150             return true;
151         }
152     }
153     
154     private AppliedPatch applyPatch(Patch patch)
155     {
156         // get the patch from the DAO
157
AppliedPatch appliedPatch = patchDaoService.getAppliedPatch(patch.getId());
158         if (appliedPatch != null && appliedPatch.getSucceeded())
159         {
160             // it has already been applied
161
if (logger.isDebugEnabled())
162             {
163                 logger.debug("Patch was already successfully applied: \n" +
164                         " patch: " + appliedPatch);
165             }
166             return appliedPatch;
167         }
168         // the execution report
169
String JavaDoc report = null;
170         boolean success = false;
171         // first check whether the patch is relevant to the repo
172
Descriptor repoDescriptor = descriptorService.getInstalledRepositoryDescriptor();
173         boolean applies = applies(repoDescriptor, patch);
174         if (!applies)
175         {
176             // create a dummy report
177
report = I18NUtil.getMessage(MSG_NOT_RELEVANT, repoDescriptor.getSchema());
178             success = true; // this succeeded because it didn't need to be applied
179
}
180         else
181         {
182             // perform actual execution
183
try
184             {
185                 report = patch.apply();
186                 success = true;
187             }
188             catch (PatchException e)
189             {
190                 // failed
191
report = e.getMessage();
192                 success = false;
193             }
194         }
195
196         Descriptor serverDescriptor = descriptorService.getServerDescriptor();
197         String JavaDoc server = (serverDescriptor.getVersion() + " - " + serverDescriptor.getEdition());
198         
199         // create or update the record of execution
200
if (appliedPatch == null)
201         {
202             appliedPatch = patchDaoService.newAppliedPatch(patch.getId());
203         }
204         // fill in the record's details
205
String JavaDoc patchDescription = I18NUtil.getMessage(patch.getDescription());
206         if (patchDescription == null)
207         {
208             logger.warn("Patch description is not available: " + patch);
209             patchDescription = "No patch description available";
210         }
211         appliedPatch.setDescription(patchDescription);
212         appliedPatch.setFixesFromSchema(patch.getFixesFromSchema());
213         appliedPatch.setFixesToSchema(patch.getFixesToSchema());
214         appliedPatch.setTargetSchema(patch.getTargetSchema()); // the schema the server is expecting
215
appliedPatch.setAppliedToSchema(repoDescriptor.getSchema()); // the old schema of the repo
216
appliedPatch.setAppliedToServer(server); // the current version and label of the server
217
appliedPatch.setAppliedOnDate(new Date JavaDoc()); // the date applied
218
appliedPatch.setSucceeded(success); // whether or not the patch succeeded
219
appliedPatch.setWasExecuted(applies); // whether or not the patch was executed
220
appliedPatch.setReport(report); // additional, human-readable, status
221

222         // done
223
if (logger.isDebugEnabled())
224         {
225             logger.debug("Applied patch: \n" + appliedPatch);
226         }
227         return appliedPatch;
228     }
229     
230     /**
231      * Check whether the patch is applicable to the particular version of the repository.
232      *
233      * @param repoDescriptor contains the version details of the repository
234      * @param patch the patch whos version must be checked
235      * @return Returns true if the patch should be applied to the repository
236      */

237     private boolean applies(Descriptor repoDescriptor, Patch patch)
238     {
239         int repoSchema = repoDescriptor.getSchema();
240         // does the patch apply?
241
boolean apply = patch.applies(repoSchema);
242         
243         // done
244
if (logger.isDebugEnabled())
245         {
246             logger.debug("Patch schema version number check against repo version: \n" +
247                     " repo schema version: " + repoDescriptor.getVersion() + "\n" +
248                     " patch: " + patch);
249         }
250         return apply;
251     }
252
253     @SuppressWarnings JavaDoc("unchecked")
254     public List JavaDoc<PatchInfo> getPatches(Date JavaDoc fromDate, Date JavaDoc toDate)
255     {
256         if (fromDate == null)
257         {
258             fromDate = ZERO_DATE;
259         }
260         if (toDate == null)
261         {
262             toDate = INFINITE_DATE;
263         }
264         List JavaDoc<? extends PatchInfo> appliedPatches = patchDaoService.getAppliedPatches(fromDate, toDate);
265         // disconnect each of these
266
for (PatchInfo appliedPatch : appliedPatches)
267         {
268             patchDaoService.detach((AppliedPatch)appliedPatch);
269         }
270         // done
271
return (List JavaDoc<PatchInfo>) appliedPatches;
272     }
273 }
274
Popular Tags