View Javadoc
1   /*
2    * Copyright (C) 2007-2012 Argeo GmbH
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *         http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.argeo.slc.client.ui.dist.commands;
17  
18  import javax.jcr.Credentials;
19  import javax.jcr.Node;
20  import javax.jcr.Property;
21  import javax.jcr.Repository;
22  import javax.jcr.RepositoryException;
23  import javax.jcr.RepositoryFactory;
24  import javax.jcr.Session;
25  import javax.jcr.nodetype.NodeType;
26  import javax.jcr.query.Query;
27  import javax.jcr.query.QueryResult;
28  import javax.jcr.util.TraversingItemVisitor;
29  
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  import org.argeo.eclipse.ui.EclipseJcrMonitor;
33  import org.argeo.jcr.JcrMonitor;
34  import org.argeo.jcr.JcrUtils;
35  import org.argeo.node.security.Keyring;
36  import org.argeo.slc.SlcException;
37  import org.argeo.slc.SlcNames;
38  import org.argeo.slc.client.ui.dist.DistPlugin;
39  import org.argeo.slc.repo.ArtifactIndexer;
40  import org.argeo.slc.repo.JarFileIndexer;
41  import org.argeo.slc.repo.ModularDistributionIndexer;
42  import org.argeo.slc.repo.PdeSourcesIndexer;
43  import org.argeo.slc.repo.RepoConstants;
44  import org.argeo.slc.repo.RepoUtils;
45  import org.eclipse.core.commands.AbstractHandler;
46  import org.eclipse.core.commands.ExecutionEvent;
47  import org.eclipse.core.commands.ExecutionException;
48  import org.eclipse.core.runtime.IProgressMonitor;
49  import org.eclipse.core.runtime.IStatus;
50  import org.eclipse.core.runtime.Status;
51  import org.eclipse.core.runtime.jobs.Job;
52  import org.eclipse.jface.dialogs.MessageDialog;
53  import org.eclipse.jface.resource.ImageDescriptor;
54  
55  /**
56   * Force the indexing of a given workspace by making sure than Maven and OSGi
57   * metadata are consistent. This mechanism normally relies on JCR Listeners but
58   * must sometimes be triggered manually
59   */
60  public class NormalizeWorkspace extends AbstractHandler implements SlcNames {
61  	private final static Log log = LogFactory.getLog(NormalizeWorkspace.class);
62  
63  	public final static String ID = DistPlugin.PLUGIN_ID + ".normalizeWorkspace";
64  	public final static ImageDescriptor DEFAULT_ICON = DistPlugin.getImageDescriptor("icons/normalize.gif");
65  
66  	public final static String PARAM_WORKSPACE_NAME = "workspaceName";
67  	public final static String PARAM_TARGET_REPO_PATH = "targetRepoPath";
68  
69  	private String artifactBasePath = RepoConstants.DEFAULT_ARTIFACTS_BASE_PATH;
70  
71  	// DEPENDENCY INJECTION
72  	private RepositoryFactory repositoryFactory;
73  	private Keyring keyring;
74  	private Repository repository;
75  
76  	// Relevant default node indexers
77  	private PdeSourcesIndexer pdeSourceIndexer = new PdeSourcesIndexer();
78  	// WARNING Order is important: must be called in the following order.
79  	private ModularDistributionIndexer modularDistributionIndexer = new ModularDistributionIndexer();
80  	private JarFileIndexer jarFileIndexer = new JarFileIndexer();
81  	private ArtifactIndexer artifactIndexer = new ArtifactIndexer();
82  
83  	public Object execute(ExecutionEvent event) throws ExecutionException {
84  		String targetRepoPath = event.getParameter(PARAM_TARGET_REPO_PATH);
85  		String wkspName = event.getParameter(PARAM_WORKSPACE_NAME);
86  
87  		Session currSession = null;
88  		NormalizeJob job;
89  		try {
90  			String msg = "Your are about to normalize workspace: " + wkspName
91  					+ ".\nThis will index OSGi bundles and Maven artifacts, "
92  					+ "it will also convert Maven sources to PDE Sources if needed.\n"
93  					+ "Note that no information will be overwritten: " + "all existing information are kept."
94  					+ "\n\n Do you really want to proceed ?";
95  
96  			if (!MessageDialog.openConfirm(DistPlugin.getDefault().getWorkbench().getDisplay().getActiveShell(),
97  					"Confirm workspace normalization", msg))
98  				return null;
99  
100 			currSession = repository.login();
101 			Node repoNode = currSession.getNode(targetRepoPath);
102 			Repository repository = RepoUtils.getRepository(repositoryFactory, keyring, repoNode);
103 			Credentials credentials = RepoUtils.getRepositoryCredentials(keyring, repoNode);
104 
105 			job = new NormalizeJob(repository.login(credentials, wkspName));
106 			job.setUser(true);
107 			job.schedule();
108 		} catch (RepositoryException e) {
109 			throw new SlcException("Cannot normalize " + wkspName, e);
110 		} finally {
111 			JcrUtils.logoutQuietly(currSession);
112 		}
113 		return null;
114 	}
115 
116 	private class NormalizeJob extends Job {
117 		private Session session;
118 
119 		public NormalizeJob(Session session) {
120 			super("Normalize Distribution");
121 			this.session = session;
122 		}
123 
124 		@Override
125 		protected IStatus run(IProgressMonitor progressMonitor) {
126 			try {
127 				JcrMonitor monitor = new EclipseJcrMonitor(progressMonitor);
128 				// Normalize artifacts
129 				Query countQuery = session.getWorkspace().getQueryManager()
130 						.createQuery("select file from [nt:file] as file", Query.JCR_SQL2);
131 				QueryResult result = countQuery.execute();
132 				Long expectedCount = result.getNodes().getSize();
133 				monitor.beginTask("Normalize artifacts of " + session.getWorkspace().getName(),
134 						expectedCount.intValue());
135 				NormalizingTraverser tiv = new NormalizingTraverser(monitor);
136 				Node artifactBaseNode = session.getNode(artifactBasePath);
137 				artifactBaseNode.accept(tiv);
138 			} catch (Exception e) {
139 				log.error("Error normalizing workspace " + session.getWorkspace().getName() + ": " + e.getMessage());
140 				if (log.isErrorEnabled())
141 					e.printStackTrace();
142 				return new Status(IStatus.ERROR, DistPlugin.PLUGIN_ID,
143 						"Cannot normalize distribution " + session.getWorkspace().getName(), e);
144 			} finally {
145 				JcrUtils.logoutQuietly(session);
146 			}
147 			return Status.OK_STATUS;
148 		}
149 	}
150 
151 	private class NormalizingTraverser extends TraversingItemVisitor {
152 		JcrMonitor monitor;
153 
154 		public NormalizingTraverser(JcrMonitor monitor) {
155 			super();
156 			this.monitor = monitor;
157 		}
158 
159 		@Override
160 		protected void entering(Property property, int level) throws RepositoryException {
161 		}
162 
163 		@Override
164 		protected void entering(Node node, int level) throws RepositoryException {
165 			if (node.getPath().startsWith(RepoConstants.DIST_DOWNLOAD_BASEPATH))
166 				return;
167 
168 			if (node.isNodeType(NodeType.NT_FILE)) {
169 				if (node.getName().endsWith("-sources.jar")) {
170 					monitor.subTask(node.getName());
171 					pdeSourceIndexer.index(node);
172 					node.getSession().save();
173 					monitor.worked(1);
174 					if (log.isDebugEnabled())
175 						log.debug("Processed source artifact " + node.getPath());
176 				} else if (node.getName().endsWith("-javadoc.jar")) {
177 					if (log.isDebugEnabled())
178 						log.debug("Skip indexing of Javadoc jar " + node.getPath());
179 				} else if (node.getName().endsWith(".jar")) {
180 					if (jarFileIndexer.support(node.getPath()))
181 						if (artifactIndexer.support(node.getPath())) {
182 							monitor.subTask(node.getName());
183 							modularDistributionIndexer.index(node);
184 							jarFileIndexer.index(node);
185 							artifactIndexer.index(node);
186 							if (node.getSession().hasPendingChanges()) {
187 								node.getSession().save();
188 								if (log.isDebugEnabled())
189 									log.debug("Processed jar artifact " + node.getPath());
190 							}
191 							monitor.worked(1);
192 						}
193 				} else if (node.getName().endsWith(".pom")) {
194 					// Removed: we do not support binaries concept anymore.
195 					// if (distBundleIndexer.support(node.getPath()))
196 					// distBundleIndexer.index(node);
197 					if (artifactIndexer.support(node.getPath()))
198 						artifactIndexer.index(node);
199 					if (node.getSession().hasPendingChanges()) {
200 						node.getSession().save();
201 						if (log.isDebugEnabled())
202 							log.debug("Processed pom artifact " + node.getPath());
203 					}
204 					monitor.worked(1);
205 				} else {
206 					monitor.worked(1);
207 				}
208 			}
209 		}
210 
211 		@Override
212 		protected void leaving(Property property, int level) throws RepositoryException {
213 		}
214 
215 		@Override
216 		protected void leaving(Node node, int level) throws RepositoryException {
217 		}
218 	}
219 
220 	/* DEPENDENCY INJECTION */
221 	public void setNodeRepository(Repository nodeRepository) {
222 		this.repository = nodeRepository;
223 	}
224 
225 	public void setRepositoryFactory(RepositoryFactory repositoryFactory) {
226 		this.repositoryFactory = repositoryFactory;
227 	}
228 
229 	public void setKeyring(Keyring keyring) {
230 		this.keyring = keyring;
231 	}
232 }