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.editors;
17  
18  import java.net.URL;
19  
20  import javax.jcr.Node;
21  import javax.jcr.RepositoryException;
22  
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  import org.argeo.slc.SlcException;
26  import org.argeo.slc.SlcNames;
27  import org.argeo.slc.build.License;
28  import org.argeo.slc.client.ui.dist.DistConstants;
29  import org.argeo.slc.client.ui.dist.utils.HyperlinkAdapter;
30  import org.argeo.slc.repo.RepoConstants;
31  import org.argeo.slc.repo.RepoUtils;
32  import org.eclipse.jface.dialogs.IMessageProvider;
33  import org.eclipse.swt.SWT;
34  import org.eclipse.swt.layout.GridData;
35  import org.eclipse.swt.layout.GridLayout;
36  import org.eclipse.swt.layout.RowLayout;
37  import org.eclipse.swt.widgets.Composite;
38  import org.eclipse.swt.widgets.Label;
39  import org.eclipse.swt.widgets.Text;
40  import org.eclipse.ui.PlatformUI;
41  import org.eclipse.ui.browser.IWebBrowser;
42  import org.eclipse.ui.browser.IWorkbenchBrowserSupport;
43  import org.eclipse.ui.forms.IManagedForm;
44  import org.eclipse.ui.forms.editor.FormEditor;
45  import org.eclipse.ui.forms.editor.FormPage;
46  import org.eclipse.ui.forms.events.HyperlinkEvent;
47  import org.eclipse.ui.forms.widgets.FormToolkit;
48  import org.eclipse.ui.forms.widgets.Hyperlink;
49  import org.eclipse.ui.forms.widgets.ScrolledForm;
50  import org.eclipse.ui.forms.widgets.Section;
51  
52  /** Show details for a given bundle. */
53  public class BundleDetailPage extends FormPage implements SlcNames {
54  	private final static Log log = LogFactory.getLog(BundleDetailPage.class);
55  
56  	final static String PAGE_ID = "BundleDetailPage";
57  
58  	// Business Objects
59  	private Node bundle;
60  
61  	// This page widgets
62  	private FormToolkit tk;
63  
64  	public BundleDetailPage(FormEditor formEditor, String title, Node bundle) {
65  		super(formEditor, PAGE_ID, title);
66  		this.bundle = bundle;
67  	}
68  
69  	@Override
70  	protected void createFormContent(IManagedForm managedForm) {
71  		// General settings for this page
72  		ScrolledForm form = managedForm.getForm();
73  		tk = managedForm.getToolkit();
74  		Composite body = form.getBody();
75  
76  		GridLayout layout = new GridLayout(1, false);
77  		layout.marginWidth = 5;
78  		layout.marginRight = 15;
79  		layout.verticalSpacing = 0;
80  		body.setLayout(layout);
81  		try {
82  			form.setText(bundle.hasProperty(SlcNames.SLC_SYMBOLIC_NAME) ? bundle
83  					.getProperty(SlcNames.SLC_SYMBOLIC_NAME).getString() : "");
84  			form.setMessage(bundle
85  					.hasProperty(DistConstants.SLC_BUNDLE_DESCRIPTION) ? bundle
86  					.getProperty(DistConstants.SLC_BUNDLE_DESCRIPTION)
87  					.getString() : "", IMessageProvider.NONE);
88  		} catch (RepositoryException re) {
89  			throw new SlcException("Unable to get bundle name for node "
90  					+ bundle, re);
91  		}
92  
93  		// Main layout
94  		Composite header = tk.createComposite(body);
95  		header.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
96  		populateHeaderPart(header);
97  
98  		Composite mavenSnipet = tk.createComposite(body);
99  		mavenSnipet.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
100 		populateMavenSnippetPart(mavenSnipet);
101 	}
102 
103 	private void populateHeaderPart(Composite parent) {
104 		GridLayout layout = new GridLayout(6, false);
105 		// layout.marginWidth = layout.horizontalSpacing = layout.marginHeight =
106 		// 0;
107 		layout.horizontalSpacing = 10;
108 		parent.setLayout(layout);
109 		try {
110 			// 1st Line: Category, name version
111 			createLT(parent, "Category",
112 					bundle.hasProperty(SlcNames.SLC_GROUP_ID) ? bundle
113 							.getProperty(SlcNames.SLC_GROUP_ID).getString()
114 							: "");
115 			createLT(parent, "Name",
116 					bundle.hasProperty(SlcNames.SLC_ARTIFACT_ID) ? bundle
117 							.getProperty(SlcNames.SLC_ARTIFACT_ID).getString()
118 							: "");
119 			createLT(parent, "Version",
120 					bundle.hasProperty(SlcNames.SLC_ARTIFACT_VERSION) ? bundle
121 							.getProperty(SlcNames.SLC_ARTIFACT_VERSION)
122 							.getString() : "");
123 
124 			// 3rd Line: Vendor, licence, sources
125 			createLT(
126 					parent,
127 					"Vendor",
128 					bundle.hasProperty(DistConstants.SLC_BUNDLE_VENDOR) ? bundle
129 							.getProperty(DistConstants.SLC_BUNDLE_VENDOR)
130 							.getString() : "N/A");
131 
132 			createLicencesLink(parent, "Licence",
133 					DistConstants.SLC_BUNDLE_LICENCE);
134 			addSourceLink(parent);
135 
136 			// 2nd Line: The Jar itself and the Manifest
137 			createJarLink(parent);
138 			createManifestLink(parent);
139 
140 			// Last line
141 			createPomLink(parent);
142 
143 		} catch (RepositoryException re) {
144 			throw new SlcException("Unable to get bundle name for node "
145 					+ bundle, re);
146 		}
147 
148 	}
149 
150 	private void populateMavenSnippetPart(Composite parent) {
151 		GridLayout layout = new GridLayout(1, false);
152 		layout.marginWidth = layout.horizontalSpacing = layout.horizontalSpacing = layout.marginHeight = 0;
153 		parent.setLayout(layout);
154 
155 		Section section = tk.createSection(parent, Section.TITLE_BAR
156 				| Section.DESCRIPTION);
157 		section.setText("Maven");
158 		section.setDescription("Add the below tag to your Artifact pom dependencies");
159 		section.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
160 		Text snippetTxt = createMavenSnippet(section);
161 		section.setClient(snippetTxt);
162 	}
163 
164 	// /////////////////////
165 	// HELPERS
166 
167 	private Text createLT(Composite parent, String labelValue, String textValue) {
168 		Label label = tk.createLabel(parent, labelValue, SWT.RIGHT);
169 		// label.setFont(EclipseUiUtils.getBoldFont(parent));
170 		label.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
171 		// Add a trailing space to workaround a display glitch in RAP 1.3
172 		Text text = new Text(parent, SWT.LEFT);
173 		text.setText(textValue + " ");
174 		text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
175 		text.setEditable(false);
176 		return text;
177 	}
178 
179 	private void createLicencesLink(Composite parent, String label,
180 			String jcrPropName) throws RepositoryException {
181 		tk.createLabel(parent, label, SWT.NONE);
182 		if (bundle.hasProperty(jcrPropName)) {
183 
184 			String licenceLinkVal = bundle.getProperty(jcrPropName).getString();
185 
186 			// FIXME Hack until license generation is done cleanly
187 			// Problem is with description that contains a "," like
188 			// "Apache License, Version 2"
189 			String[] licenceVals;
190 			if (licenceLinkVal.contains("description="))
191 				licenceVals = new String[] { licenceLinkVal };
192 			else
193 				// multiple license, form non-regenerated manifests
194 				licenceVals = licenceLinkVal.split(", ");
195 
196 			Composite body = tk.createComposite(parent);
197 			body.setLayout(new RowLayout(SWT.WRAP));
198 
199 			for (final String value : licenceVals) {
200 				final License currLicense = parseLicenseString(value);
201 
202 				Hyperlink link = tk.createHyperlink(body,
203 						currLicense.getName(), SWT.NONE);
204 				link.addHyperlinkListener(new HyperlinkAdapter() {
205 					@Override
206 					public void linkActivated(HyperlinkEvent e) {
207 						try {
208 							IWorkbenchBrowserSupport browserSupport = PlatformUI
209 									.getWorkbench().getBrowserSupport();
210 							IWebBrowser browser = browserSupport
211 									.createBrowser(
212 											IWorkbenchBrowserSupport.LOCATION_BAR
213 													| IWorkbenchBrowserSupport.NAVIGATION_BAR,
214 											"SLC Distribution browser",
215 											"SLC Distribution browser",
216 											"A tool tip");
217 							browser.openURL(new URL(currLicense.getUri()));
218 						} catch (Exception ex) {
219 							throw new SlcException("error opening browser", ex); //$NON-NLS-1$
220 						}
221 					}
222 				});
223 			}
224 		} else
225 			tk.createLabel(parent, "N/A", SWT.NONE);
226 	}
227 
228 	// TODO this must be moved to a better place once the standard has been
229 	// defined
230 	// Enable licence encoding in a single JCR Value
231 	private final static String LICENSE_SEPARATOR = ";";
232 	// The human readable name of the licence
233 	private final static String LICENSE_NAME = "description";
234 	// A link on the internet with some more info on this licence
235 	private final static String LICENSE_LINK = "link";
236 
237 	private License parseLicenseString(String licenseStr) {
238 		String uri = null, name = null, link = null, text = null;
239 		// TODO enhance this
240 		String[] values = licenseStr.split(LICENSE_SEPARATOR);
241 		for (String value : values) {
242 			if (value.startsWith(LICENSE_NAME))
243 				name = value.substring(LICENSE_NAME.length() + 1); // +1 for the
244 																	// '='
245 			else if (value.startsWith(LICENSE_LINK))
246 				link = value.substring(LICENSE_LINK.length() + 1);
247 			else if (uri == null)
248 				uri = value;
249 			// TODO manage text
250 		}
251 		return new SimpleLicense(name, uri, link, text);
252 	}
253 
254 	class SimpleLicense implements License {
255 		private final String name;
256 		private final String uri;
257 		private final String link;
258 		private final String text;
259 
260 		public SimpleLicense(String name, String uri, String link, String text) {
261 			if (uri == null)
262 				throw new SlcException(
263 						"Cannot manage a licence with a null URI ");
264 			this.uri = uri;
265 
266 			this.name = name;
267 			this.link = link;
268 			this.text = text;
269 		}
270 
271 		public String getUri() {
272 			return uri;
273 		}
274 
275 		public String getText() {
276 			return text;
277 		}
278 
279 		public String getName() {
280 			return name != null ? name : uri;
281 		}
282 
283 		public String getLink() {
284 			return link;
285 		}
286 	}
287 
288 	private void createJarLink(Composite parent) throws RepositoryException {
289 		Label label = tk.createLabel(parent, "Jar", SWT.RIGHT);
290 		label.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
291 
292 		Composite body = tk.createComposite(parent);
293 		RowLayout rl = new RowLayout(SWT.HORIZONTAL);
294 		rl.spacing = 6;
295 		body.setLayout(rl);
296 		body.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1));
297 
298 		Hyperlink jarLink = tk
299 				.createHyperlink(body, bundle.getName(), SWT.NONE);
300 		jarLink.addHyperlinkListener(new OpenFileLinkListener(bundle.getPath()));
301 
302 		// Corresponding check sums
303 
304 		String name = bundle.getName() + ".md5";
305 		if (bundle.getParent().hasNode(name)) {
306 			Node md5 = bundle.getParent().getNode(name);
307 			Hyperlink md5Link = tk.createHyperlink(body, "MD5", SWT.NONE);
308 			md5Link.addHyperlinkListener(new OpenFileLinkListener(md5.getPath()));
309 		}
310 
311 		name = bundle.getName() + ".sha1";
312 		if (bundle.getParent().hasNode(name)) {
313 			Node sha1 = bundle.getParent().getNode(name);
314 			Hyperlink sha1Link = tk.createHyperlink(body, "SHA1", SWT.NONE);
315 			sha1Link.addHyperlinkListener(new OpenFileLinkListener(sha1
316 					.getPath()));
317 		}
318 	}
319 
320 	private void createPomLink(Composite parent) throws RepositoryException {
321 		Label label = tk.createLabel(parent, "Pom", SWT.RIGHT);
322 		label.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
323 
324 		String name = bundle.getName().substring(0,
325 				bundle.getName().length() - "jar".length())
326 				+ "pom";
327 
328 		if (bundle.getParent().hasNode(name)) {
329 			Node pom = bundle.getParent().getNode(name);
330 
331 			Composite body = tk.createComposite(parent);
332 			RowLayout rl = new RowLayout(SWT.HORIZONTAL);
333 			rl.spacing = 6;
334 			body.setLayout(rl);
335 			body.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false,
336 					3, 1));
337 
338 			Hyperlink pomLink = tk.createHyperlink(body, "pom.xml", SWT.NONE);
339 			pomLink.addHyperlinkListener(new OpenFileLinkListener(pom.getPath()));
340 
341 			// Corresponding check sums
342 			name = pom.getName() + ".md5";
343 			if (pom.getParent().hasNode(name)) {
344 				Node md5 = pom.getParent().getNode(name);
345 				Hyperlink md5Link = tk.createHyperlink(body, "MD5", SWT.NONE);
346 				md5Link.addHyperlinkListener(new OpenFileLinkListener(md5
347 						.getPath()));
348 			}
349 
350 			name = pom.getName() + ".sha1";
351 			if (pom.getParent().hasNode(name)) {
352 				Node sha1 = pom.getParent().getNode(name);
353 				Hyperlink sha1Link = tk.createHyperlink(body, "SHA1", SWT.NONE);
354 				sha1Link.addHyperlinkListener(new OpenFileLinkListener(sha1
355 						.getPath()));
356 			}
357 		} else
358 			tk.createLabel(parent, "N/A", SWT.NONE);
359 	}
360 
361 	private void createManifestLink(Composite parent)
362 			throws RepositoryException {
363 		tk.createLabel(parent, "Manifest", SWT.NONE);
364 		// Hyperlink link =
365 		// TODO fix this when file download has been implemented for the
366 		// manifest
367 		tk.createHyperlink(parent, "MANIFEST.MF", SWT.NONE);
368 		// link.addHyperlinkListener(new
369 		// OpenFileLinkListener(bundle.getPath()));
370 	}
371 
372 	// private void createHyperlink(Composite parent, String label,
373 	// String jcrPropName) throws RepositoryException {
374 	// tk.createLabel(parent, label, SWT.NONE);
375 	// if (bundle.hasProperty(jcrPropName)) {
376 	// final Hyperlink link = tk.createHyperlink(parent, bundle
377 	// .getProperty(jcrPropName).getString(), SWT.NONE);
378 	// link.addHyperlinkListener(new AbstractHyperlinkListener() {
379 	// @Override
380 	// public void linkActivated(HyperlinkEvent e) {
381 	// try {
382 	// IWorkbenchBrowserSupport browserSupport = PlatformUI
383 	// .getWorkbench().getBrowserSupport();
384 	// IWebBrowser browser = browserSupport
385 	// .createBrowser(
386 	// IWorkbenchBrowserSupport.LOCATION_BAR
387 	// | IWorkbenchBrowserSupport.NAVIGATION_BAR,
388 	// "SLC Distribution browser",
389 	// "SLC Distribution browser",
390 	// "A tool tip");
391 	// browser.openURL(new URL(link.getText()));
392 	// } catch (Exception ex) {
393 	//						throw new SlcException("error opening browser", ex); //$NON-NLS-1$
394 	// }
395 	// }
396 	// });
397 	// } else
398 	// tk.createLabel(parent, "N/A", SWT.NONE);
399 	// }
400 
401 	// helper to check if sources are available
402 	private void addSourceLink(Composite parent) {
403 		try {
404 			String srcPath = RepoUtils.relatedPdeSourcePath(
405 					RepoConstants.DEFAULT_ARTIFACTS_BASE_PATH, bundle);
406 			if (!bundle.getSession().nodeExists(srcPath)) {
407 				createLT(parent, "Sources", "N/A");
408 			} else {
409 				final Node sourcesNode = bundle.getSession().getNode(srcPath);
410 
411 				String srcName = null;
412 				if (sourcesNode.hasProperty(SlcNames.SLC_SYMBOLIC_NAME))
413 					srcName = sourcesNode.getProperty(
414 							SlcNames.SLC_SYMBOLIC_NAME).getString();
415 				else
416 					srcName = sourcesNode.getName();
417 				Label label = tk.createLabel(parent, "Sources", SWT.RIGHT);
418 				label.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false,
419 						false));
420 				final Hyperlink link = tk.createHyperlink(parent, srcName,
421 						SWT.NONE);
422 				link.addHyperlinkListener(new OpenFileLinkListener(sourcesNode
423 						.getPath()));
424 
425 				// {
426 				// @Override
427 				// public void linkActivated(HyperlinkEvent e) {
428 				// try {
429 				// ModuleEditorInput editorInput = (ModuleEditorInput)
430 				// getEditorInput();
431 				// Map<String, String> params = new HashMap<String, String>();
432 				// params.put(OpenJcrFile.PARAM_REPO_NODE_PATH,
433 				// editorInput.getRepoNodePath());
434 				// params.put(OpenJcrFile.PARAM_REPO_URI,
435 				// editorInput.getUri());
436 				// params.put(OpenJcrFile.PARAM_WORKSPACE_NAME,
437 				// editorInput.getWorkspaceName());
438 				// params.put(OpenJcrFile.PARAM_FILE_PATH,
439 				// );
440 				// CommandUtils.callCommand(OpenJcrFile.ID, params);
441 				// } catch (Exception ex) {
442 				//							throw new SlcException("error opening browser", ex); //$NON-NLS-1$
443 				// }
444 				// }
445 				// });
446 
447 			}
448 		} catch (RepositoryException e) {
449 			throw new SlcException("Unable to configure sources link for "
450 					+ bundle, e);
451 		}
452 	}
453 
454 	private class OpenFileLinkListener extends HyperlinkAdapter {
455 		final private String path;
456 
457 		public OpenFileLinkListener(String path) {
458 			this.path = path;
459 		}
460 
461 		@Override
462 		public void linkActivated(HyperlinkEvent e) {
463 			log.warn("File download must be implemented. Cannot provide access to "
464 					+ path);
465 
466 			// try {
467 			// ModuleEditorInput editorInput = (ModuleEditorInput)
468 			// getEditorInput();
469 			// Map<String, String> params = new HashMap<String, String>();
470 			// params.put(OpenJcrFile.PARAM_REPO_NODE_PATH,
471 			// editorInput.getRepoNodePath());
472 			// params.put(OpenJcrFile.PARAM_REPO_URI, editorInput.getUri());
473 			// params.put(OpenJcrFile.PARAM_WORKSPACE_NAME,
474 			// editorInput.getWorkspaceName());
475 			// params.put(OpenJcrFile.PARAM_FILE_PATH, path);
476 			//
477 			// String cmdId = (new OpenJcrFileCmdId()).getCmdId();
478 			// if (log.isTraceEnabled())
479 			// log.debug("Retrieved openFile Cmd ID: " + cmdId);
480 			// CommandUtils.callCommand(cmdId, params);
481 			// } catch (Exception ex) {
482 			//				throw new SlcException("error opening browser", ex); //$NON-NLS-1$
483 			// }
484 		}
485 	}
486 
487 	/** Creates a text area with corresponding maven snippet */
488 	private Text createMavenSnippet(Composite parent) {
489 		Text mavenSnippet = new Text(parent, SWT.MULTI | SWT.WRAP);
490 		GridData gd = new GridData(GridData.FILL_HORIZONTAL);
491 		gd.grabExcessHorizontalSpace = true;
492 		gd.heightHint = 100;
493 		mavenSnippet.setLayoutData(gd);
494 		mavenSnippet.setText(generateXmlSnippet());
495 		return mavenSnippet;
496 	}
497 
498 	private String generateXmlSnippet() {
499 		try {
500 			StringBuffer sb = new StringBuffer();
501 			sb.append("<dependency>\n");
502 			sb.append("\t<groupId>");
503 			sb.append(bundle.getProperty(SLC_GROUP_ID).getString());
504 			sb.append("</groupId>\n");
505 			sb.append("\t<artifactId>");
506 			sb.append(bundle.getProperty(SLC_ARTIFACT_ID).getString());
507 			sb.append("</artifactId>\n");
508 			sb.append("\t<version>");
509 			sb.append(bundle.getProperty(SLC_ARTIFACT_VERSION).getString());
510 			sb.append("</version>\n");
511 			sb.append("</dependency>");
512 			return sb.toString();
513 		} catch (RepositoryException re) {
514 			throw new SlcException(
515 					"unexpected error while generating maven snippet");
516 		}
517 	}
518 }