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.Binary;
19  import javax.jcr.Credentials;
20  import javax.jcr.Node;
21  import javax.jcr.NodeIterator;
22  import javax.jcr.Property;
23  import javax.jcr.Repository;
24  import javax.jcr.RepositoryException;
25  import javax.jcr.RepositoryFactory;
26  import javax.jcr.Session;
27  import javax.jcr.nodetype.NodeType;
28  import javax.jcr.query.Query;
29  import javax.jcr.query.QueryResult;
30  import javax.jcr.util.TraversingItemVisitor;
31  
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  import org.argeo.eclipse.ui.EclipseJcrMonitor;
35  import org.argeo.jcr.JcrMonitor;
36  import org.argeo.jcr.JcrUtils;
37  import org.argeo.node.security.Keyring;
38  import org.argeo.slc.NameVersion;
39  import org.argeo.slc.SlcException;
40  import org.argeo.slc.SlcNames;
41  import org.argeo.slc.SlcTypes;
42  import org.argeo.slc.client.ui.dist.DistPlugin;
43  import org.argeo.slc.repo.ArtifactIndexer;
44  import org.argeo.slc.repo.JarFileIndexer;
45  import org.argeo.slc.repo.RepoConstants;
46  import org.argeo.slc.repo.RepoUtils;
47  import org.argeo.slc.repo.maven.AetherUtils;
48  import org.argeo.slc.repo.maven.MavenConventionsUtils;
49  import org.argeo.slc.repo.osgi.NormalizeGroup;
50  import org.eclipse.aether.artifact.Artifact;
51  import org.eclipse.aether.artifact.DefaultArtifact;
52  import org.eclipse.core.commands.AbstractHandler;
53  import org.eclipse.core.commands.ExecutionEvent;
54  import org.eclipse.core.commands.ExecutionException;
55  import org.eclipse.core.runtime.IProgressMonitor;
56  import org.eclipse.core.runtime.IStatus;
57  import org.eclipse.core.runtime.Status;
58  import org.eclipse.core.runtime.jobs.Job;
59  import org.eclipse.jface.dialogs.Dialog;
60  import org.eclipse.jface.dialogs.IMessageProvider;
61  import org.eclipse.jface.dialogs.TitleAreaDialog;
62  import org.eclipse.jface.resource.ImageDescriptor;
63  import org.eclipse.swt.SWT;
64  import org.eclipse.swt.graphics.Point;
65  import org.eclipse.swt.layout.GridData;
66  import org.eclipse.swt.layout.GridLayout;
67  import org.eclipse.swt.widgets.Button;
68  import org.eclipse.swt.widgets.Composite;
69  import org.eclipse.swt.widgets.Control;
70  import org.eclipse.swt.widgets.Label;
71  import org.eclipse.swt.widgets.Shell;
72  import org.eclipse.swt.widgets.Text;
73  import org.eclipse.ui.handlers.HandlerUtil;
74  
75  /** Legacy - Make sure than Maven and OSGi metadata are consistent */
76  public class NormalizeDistribution extends AbstractHandler implements SlcNames {
77  	private final static Log log = LogFactory
78  			.getLog(NormalizeDistribution.class);
79  
80  	public final static String ID = DistPlugin.PLUGIN_ID
81  			+ ".normalizeDistribution";
82  	public final static String DEFAULT_LABEL = "Legacy Normalization...";
83  	public final static ImageDescriptor DEFAULT_ICON = DistPlugin
84  			.getImageDescriptor("icons/normalize.gif");
85  
86  	public final static String PARAM_WORKSPACE_NAME = "workspaceName";
87  	public final static String PARAM_TARGET_REPO_PATH = "targetRepoPath";
88  
89  	private String artifactBasePath = RepoConstants.DEFAULT_ARTIFACTS_BASE_PATH;
90  
91  	private ArtifactIndexer artifactIndexer = new ArtifactIndexer();
92  	private JarFileIndexer jarFileIndexer = new JarFileIndexer();
93  
94  	// DEPENDENCY INJECTION
95  	private RepositoryFactory repositoryFactory;
96  	private Keyring keyring;
97  	private Repository nodeRepository;
98  
99  	public Object execute(ExecutionEvent event) throws ExecutionException {
100 
101 		String targetRepoPath = event.getParameter(PARAM_TARGET_REPO_PATH);
102 		String wkspName = event.getParameter(PARAM_WORKSPACE_NAME);
103 
104 		Session nodeSession = null;
105 		NormalizeJob job;
106 		try {
107 
108 			NormalizationDialog dialog = new NormalizationDialog(
109 					HandlerUtil.getActiveShell(event));
110 			if (dialog.open() != Dialog.OK)
111 				return null;
112 
113 			nodeSession = nodeRepository.login();
114 			Node repoNode = nodeSession.getNode(targetRepoPath);
115 			Repository repository = RepoUtils.getRepository(repositoryFactory,
116 					keyring, repoNode);
117 			Credentials credentials = RepoUtils.getRepositoryCredentials(
118 					keyring, repoNode);
119 
120 			String version = dialog.getVersion();
121 			Boolean overridePoms = dialog.getOverridePoms();
122 
123 			job = new NormalizeJob(repository.login(credentials, wkspName),
124 					version, overridePoms);
125 			job.setUser(true);
126 			job.schedule();
127 		} catch (RepositoryException e) {
128 			throw new SlcException("Cannot normalize " + wkspName, e);
129 		} finally {
130 			JcrUtils.logoutQuietly(nodeSession);
131 		}
132 		return null;
133 	}
134 
135 	protected void packageSourcesAsPdeSource(Node sourcesNode) {
136 		Binary origBinary = null;
137 		Binary osgiBinary = null;
138 		try {
139 			Session session = sourcesNode.getSession();
140 			Artifact sourcesArtifact = AetherUtils.convertPathToArtifact(
141 					sourcesNode.getPath(), null);
142 
143 			// read name version from manifest
144 			Artifact osgiArtifact = new DefaultArtifact(
145 					sourcesArtifact.getGroupId(),
146 					sourcesArtifact.getArtifactId(),
147 					sourcesArtifact.getExtension(),
148 					sourcesArtifact.getVersion());
149 			String osgiPath = MavenConventionsUtils.artifactPath(
150 					artifactBasePath, osgiArtifact);
151 			osgiBinary = session.getNode(osgiPath).getNode(Node.JCR_CONTENT)
152 					.getProperty(Property.JCR_DATA).getBinary();
153 
154 			NameVersion nameVersion = RepoUtils.readNameVersion(osgiBinary
155 					.getStream());
156 
157 			// create PDe sources artifact
158 			Artifact pdeSourceArtifact = new DefaultArtifact(
159 					sourcesArtifact.getGroupId(),
160 					sourcesArtifact.getArtifactId() + ".source",
161 					sourcesArtifact.getExtension(),
162 					sourcesArtifact.getVersion());
163 			String targetSourceParentPath = MavenConventionsUtils
164 					.artifactParentPath(artifactBasePath, pdeSourceArtifact);
165 			String targetSourceFileName = MavenConventionsUtils
166 					.artifactFileName(pdeSourceArtifact);
167 			String targetSourceJarPath = targetSourceParentPath + '/'
168 					+ targetSourceFileName;
169 
170 			Node targetSourceParentNode = JcrUtils.mkfolders(session,
171 					targetSourceParentPath);
172 			origBinary = sourcesNode.getNode(Node.JCR_CONTENT)
173 					.getProperty(Property.JCR_DATA).getBinary();
174 			byte[] targetJarBytes = RepoUtils.packageAsPdeSource(
175 					origBinary.getStream(), nameVersion);
176 			JcrUtils.copyBytesAsFile(targetSourceParentNode,
177 					targetSourceFileName, targetJarBytes);
178 
179 			// reindex
180 			Node targetSourceJarNode = session.getNode(targetSourceJarPath);
181 			artifactIndexer.index(targetSourceJarNode);
182 			jarFileIndexer.index(targetSourceJarNode);
183 		} catch (RepositoryException e) {
184 			throw new SlcException("Cannot add PDE sources for " + sourcesNode,
185 					e);
186 		} finally {
187 			JcrUtils.closeQuietly(origBinary);
188 			JcrUtils.closeQuietly(osgiBinary);
189 		}
190 
191 	}
192 
193 	private class NormalizeJob extends Job {
194 		private Session session;
195 		private String version;
196 		private Boolean overridePoms;
197 
198 		public NormalizeJob(Session session, String version,
199 				Boolean overridePoms) {
200 			super("Normalize Distribution");
201 			this.session = session;
202 			this.version = version;
203 			this.overridePoms = overridePoms;
204 		}
205 
206 		@Override
207 		protected IStatus run(IProgressMonitor progressMonitor) {
208 
209 			try {
210 				JcrMonitor monitor = new EclipseJcrMonitor(progressMonitor);
211 				// normalize artifacts
212 				Query countQuery = session
213 						.getWorkspace()
214 						.getQueryManager()
215 						.createQuery("select file from [nt:file] as file",
216 								Query.JCR_SQL2);
217 				QueryResult result = countQuery.execute();
218 				Long expectedCount = result.getNodes().getSize();
219 				monitor.beginTask("Normalize artifacts of "
220 						+ session.getWorkspace().getName(),
221 						expectedCount.intValue());
222 				NormalizingTraverser tiv = new NormalizingTraverser(monitor);
223 				session.getNode(artifactBasePath).accept(tiv);
224 
225 				// normalize groups
226 				Query groupQuery = session
227 						.getWorkspace()
228 						.getQueryManager()
229 						.createQuery(
230 								"select group from [" + SlcTypes.SLC_GROUP_BASE
231 										+ "] as group", Query.JCR_SQL2);
232 				NodeIterator groups = groupQuery.execute().getNodes();
233 				monitor.beginTask("Normalize groups of "
234 						+ session.getWorkspace().getName(),
235 						(int) groups.getSize());
236 				while (groups.hasNext()) {
237 					NormalizeGroup.processGroupNode(groups.nextNode(), version,
238 							overridePoms, monitor);
239 				}
240 			} catch (Exception e) {
241 				return new Status(IStatus.ERROR, DistPlugin.PLUGIN_ID,
242 						"Cannot normalize distribution "
243 								+ session.getWorkspace().getName(), e);
244 			} finally {
245 				JcrUtils.logoutQuietly(session);
246 			}
247 			return Status.OK_STATUS;
248 		}
249 
250 	}
251 
252 	private class NormalizingTraverser extends TraversingItemVisitor {
253 		JcrMonitor monitor;
254 
255 		public NormalizingTraverser(JcrMonitor monitor) {
256 			super();
257 			this.monitor = monitor;
258 		}
259 
260 		@Override
261 		protected void entering(Property property, int level)
262 				throws RepositoryException {
263 		}
264 
265 		@Override
266 		protected void entering(Node node, int level)
267 				throws RepositoryException {
268 			if (node.isNodeType(NodeType.NT_FILE)) {
269 				if (node.getName().endsWith("-sources.jar")) {
270 					monitor.subTask(node.getName());
271 					packageSourcesAsPdeSource(node);
272 					node.getSession().save();
273 					monitor.worked(1);
274 					if (log.isDebugEnabled())
275 						log.debug("Processed source artifact " + node.getPath());
276 				} else if (node.getName().endsWith(".jar")) {
277 					if (jarFileIndexer.support(node.getPath()))
278 						if (artifactIndexer.support(node.getPath())) {
279 							monitor.subTask(node.getName());
280 							artifactIndexer.index(node);
281 							jarFileIndexer.index(node);
282 							node.getSession().save();
283 							monitor.worked(1);
284 							if (log.isDebugEnabled())
285 								log.debug("Processed artifact "
286 										+ node.getPath());
287 						}
288 				} else {
289 					monitor.worked(1);
290 				}
291 			}
292 		}
293 
294 		@Override
295 		protected void leaving(Property property, int level)
296 				throws RepositoryException {
297 		}
298 
299 		@Override
300 		protected void leaving(Node node, int level) throws RepositoryException {
301 		}
302 
303 	}
304 
305 	public class NormalizationDialog extends TitleAreaDialog {
306 		private static final long serialVersionUID = -3103886455862638580L;
307 
308 		private Text versionT;
309 		private String version;
310 		private Button overridePomsC;
311 		private Boolean overridePoms;
312 
313 		public NormalizationDialog(Shell parentShell) {
314 			super(parentShell);
315 		}
316 
317 		protected Point getInitialSize() {
318 			return new Point(300, 250);
319 		}
320 
321 		protected Control createDialogArea(Composite parent) {
322 			Composite dialogarea = (Composite) super.createDialogArea(parent);
323 			dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
324 					true));
325 			Composite composite = new Composite(dialogarea, SWT.NONE);
326 			composite.setLayout(new GridLayout(2, false));
327 			composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
328 					false));
329 			versionT = createLT(composite, "Version");
330 			overridePomsC = createLC(composite, "Override POMs");
331 			setMessage("Configure normalization", IMessageProvider.NONE);
332 
333 			parent.pack();
334 			return composite;
335 		}
336 
337 		@Override
338 		protected void okPressed() {
339 			version = versionT.getText();
340 			overridePoms = overridePomsC.getSelection();
341 			super.okPressed();
342 		}
343 
344 		/** Creates label and text. */
345 		protected Text createLT(Composite parent, String label) {
346 			new Label(parent, SWT.NONE).setText(label);
347 			Text text = new Text(parent, SWT.SINGLE | SWT.LEAD | SWT.BORDER
348 					| SWT.NONE);
349 			text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
350 			return text;
351 		}
352 
353 		/** Creates label and check. */
354 		protected Button createLC(Composite parent, String label) {
355 			new Label(parent, SWT.NONE).setText(label);
356 			Button check = new Button(parent, SWT.CHECK);
357 			check.setSelection(false);
358 			check.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
359 			return check;
360 		}
361 
362 		protected void configureShell(Shell shell) {
363 			super.configureShell(shell);
364 			shell.setText("Normalize...");
365 		}
366 
367 		public String getVersion() {
368 			return version;
369 		}
370 
371 		public Boolean getOverridePoms() {
372 			return overridePoms;
373 		}
374 
375 	}
376 
377 	/* DEPENDENCY INJECTION */
378 	public void setNodeRepository(Repository nodeRepository) {
379 		this.nodeRepository = nodeRepository;
380 	}
381 
382 	public void setRepositoryFactory(RepositoryFactory repositoryFactory) {
383 		this.repositoryFactory = repositoryFactory;
384 	}
385 
386 	public void setKeyring(Keyring keyring) {
387 		this.keyring = keyring;
388 	}
389 }