1 /******************************************************************************* 2 * Copyright (c) 2005, 2015 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 * EclipseSource Corporation - ongoing enhancements 14 *******************************************************************************/ 15 package org.eclipse.pde.internal.ui.wizards.product; 16 17 import java.io.*; 18 import java.lang.reflect.InvocationTargetException; 19 import java.net.MalformedURLException; 20 import java.net.URL; 21 import org.eclipse.core.resources.*; 22 import org.eclipse.core.runtime.*; 23 import org.eclipse.osgi.util.NLS; 24 import org.eclipse.pde.core.IBaseModel; 25 import org.eclipse.pde.core.plugin.*; 26 import org.eclipse.pde.internal.core.TargetPlatformHelper; 27 import org.eclipse.pde.internal.core.iproduct.IProduct; 28 import org.eclipse.pde.internal.core.plugin.WorkspacePluginModelBase; 29 import org.eclipse.pde.internal.ui.PDEPlugin; 30 import org.eclipse.pde.internal.ui.PDEUIMessages; 31 import org.eclipse.pde.internal.ui.util.ModelModification; 32 import org.eclipse.pde.internal.ui.util.PDEModelUtility; 33 import org.eclipse.pde.internal.ui.wizards.templates.ControlStack; 34 import org.eclipse.pde.ui.templates.IVariableProvider; 35 import org.eclipse.swt.widgets.Shell; 36 37 public class ProductIntroOperation extends BaseManifestOperation implements IVariableProvider { 38 39 protected String fIntroId; 40 private Shell fShell; 41 private IProduct fProduct; 42 private IProject fProject; 43 private static final String INTRO_POINT = "org.eclipse.ui.intro"; //$NON-NLS-1$ 44 private static final String INTRO_CONFIG_POINT = "org.eclipse.ui.intro.config"; //$NON-NLS-1$ 45 private static final String INTRO_CLASS = "org.eclipse.ui.intro.config.CustomizableIntroPart"; //$NON-NLS-1$ 46 private static final String KEY_PRODUCT_NAME = "productName"; //$NON-NLS-1$ 47 ProductIntroOperation(IProduct product, String pluginId, String introId, Shell shell)48 public ProductIntroOperation(IProduct product, String pluginId, String introId, Shell shell) { 49 super(shell, pluginId); 50 fIntroId = introId; 51 fProduct = product; 52 fProject = PluginRegistry.findModel(pluginId).getUnderlyingResource().getProject(); 53 } 54 55 @Override run(IProgressMonitor monitor)56 public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { 57 try { 58 IFile file = getFile(); 59 if (!file.exists()) { 60 createNewFile(file); 61 } else { 62 modifyExistingFile(file, monitor); 63 } 64 updateSingleton(monitor); 65 generateFiles(monitor); 66 } catch (CoreException e) { 67 throw new InvocationTargetException(e); 68 } 69 } 70 createNewFile(IFile file)71 private void createNewFile(IFile file) throws CoreException { 72 WorkspacePluginModelBase model = (WorkspacePluginModelBase) getModel(file); 73 IPluginBase base = model.getPluginBase(); 74 base.setSchemaVersion(TargetPlatformHelper.getSchemaVersion()); 75 base.add(createIntroExtension(model)); 76 base.add(createIntroConfigExtension(model)); 77 model.save(); 78 } 79 createIntroExtension(IPluginModelBase model)80 private IPluginExtension createIntroExtension(IPluginModelBase model) throws CoreException { 81 IPluginExtension extension = model.getFactory().createExtension(); 82 extension.setPoint(INTRO_POINT); 83 extension.add(createIntroExtensionContent(extension)); 84 extension.add(createIntroBindingExtensionContent(extension)); 85 return extension; 86 } 87 createIntroConfigExtension(IPluginModelBase model)88 private IPluginExtension createIntroConfigExtension(IPluginModelBase model) throws CoreException { 89 IPluginExtension extension = model.getFactory().createExtension(); 90 extension.setPoint(INTRO_CONFIG_POINT); 91 extension.add(createIntroConfigExtensionContent(extension)); 92 return extension; 93 } 94 createIntroExtensionContent(IPluginExtension extension)95 private IPluginElement createIntroExtensionContent(IPluginExtension extension) throws CoreException { 96 IPluginElement element = extension.getModel().getFactory().createElement(extension); 97 element.setName("intro"); //$NON-NLS-1$ 98 element.setAttribute("id", fIntroId); //$NON-NLS-1$ 99 element.setAttribute("class", INTRO_CLASS); //$NON-NLS-1$ 100 return element; 101 } 102 createIntroBindingExtensionContent(IPluginExtension extension)103 private IPluginElement createIntroBindingExtensionContent(IPluginExtension extension) throws CoreException { 104 IPluginElement element = extension.getModel().getFactory().createElement(extension); 105 element.setName("introProductBinding"); //$NON-NLS-1$ 106 element.setAttribute("productId", fProduct.getProductId()); //$NON-NLS-1$ 107 element.setAttribute("introId", fIntroId); //$NON-NLS-1$ 108 return element; 109 } 110 createIntroConfigExtensionContent(IPluginExtension extension)111 private IPluginElement createIntroConfigExtensionContent(IPluginExtension extension) throws CoreException { 112 IPluginElement element = extension.getModel().getFactory().createElement(extension); 113 element.setName("config"); //$NON-NLS-1$ 114 element.setAttribute("id", fPluginId + ".introConfigId"); //$NON-NLS-1$ //$NON-NLS-2$ 115 element.setAttribute("introId", fIntroId); //$NON-NLS-1$ 116 element.setAttribute("content", "introContent.xml"); //$NON-NLS-1$ //$NON-NLS-2$ 117 element.add(createPresentationElement(element)); 118 119 return element; 120 } 121 createPresentationElement(IPluginElement parent)122 private IPluginElement createPresentationElement(IPluginElement parent) throws CoreException { 123 IPluginElement presentation = null; 124 IPluginElement implementation = null; 125 IExtensionsModelFactory factory = parent.getModel().getFactory(); 126 127 presentation = factory.createElement(parent); 128 presentation.setName("presentation"); //$NON-NLS-1$ 129 presentation.setAttribute("home-page-id", "root"); //$NON-NLS-1$ //$NON-NLS-2$ 130 131 implementation = factory.createElement(presentation); 132 implementation.setName("implementation"); //$NON-NLS-1$ 133 implementation.setAttribute("kind", "html"); //$NON-NLS-1$ //$NON-NLS-2$ 134 implementation.setAttribute("style", "content/shared.css"); //$NON-NLS-1$ //$NON-NLS-2$ 135 implementation.setAttribute("os", "win32,linux,macosx"); //$NON-NLS-1$ //$NON-NLS-2$ 136 137 presentation.add(implementation); 138 139 return presentation; 140 } 141 modifyExistingFile(IFile file, IProgressMonitor monitor)142 private void modifyExistingFile(IFile file, IProgressMonitor monitor) throws CoreException { 143 IStatus status = PDEPlugin.getWorkspace().validateEdit(new IFile[] {file}, fShell); 144 if (status.getSeverity() != IStatus.OK) 145 throw new CoreException(new Status(IStatus.ERROR, "org.eclipse.pde.ui", IStatus.ERROR, NLS.bind(PDEUIMessages.ProductDefinitionOperation_readOnly, fPluginId), null)); //$NON-NLS-1$ 146 147 ModelModification mod = new ModelModification(file) { 148 @Override 149 protected void modifyModel(IBaseModel model, IProgressMonitor monitor) throws CoreException { 150 if (!(model instanceof IPluginModelBase)) 151 return; 152 IPluginModelBase pluginModel = (IPluginModelBase) model; 153 IPluginExtension extension = getExtension(pluginModel, INTRO_POINT); 154 if (extension == null) { 155 extension = createIntroExtension(pluginModel); 156 pluginModel.getPluginBase().add(extension); 157 } else { 158 extension.add(createIntroExtensionContent(extension)); 159 extension.add(createIntroBindingExtensionContent(extension)); 160 } 161 162 extension = getExtension(pluginModel, INTRO_CONFIG_POINT); 163 if (extension == null) { 164 extension = createIntroConfigExtension(pluginModel); 165 pluginModel.getPluginBase().add(extension); 166 } else { 167 extension.add(createIntroConfigExtensionContent(extension)); 168 } 169 } 170 }; 171 PDEModelUtility.modifyModel(mod, monitor); 172 } 173 getExtension(IPluginModelBase model, String tPoint)174 private IPluginExtension getExtension(IPluginModelBase model, String tPoint) { 175 IPluginExtension[] extensions = model.getPluginBase().getExtensions(); 176 for (IPluginExtension extension : extensions) { 177 String point = extension.getPoint(); 178 if (tPoint.equals(point)) { 179 return extension; 180 } 181 } 182 return null; 183 } 184 generateFiles(IProgressMonitor monitor)185 protected void generateFiles(IProgressMonitor monitor) throws CoreException { 186 monitor.setTaskName(PDEUIMessages.AbstractTemplateSection_generating); 187 188 URL locationUrl = null; 189 try { 190 locationUrl = new URL(PDEPlugin.getDefault().getInstallURL(), "templates_3.1/intro/"); //$NON-NLS-1$ 191 } catch (MalformedURLException e1) { 192 return; 193 } 194 try { 195 locationUrl = FileLocator.resolve(locationUrl); 196 locationUrl = FileLocator.toFileURL(locationUrl); 197 } catch (IOException e) { 198 return; 199 } 200 if ("file".equals(locationUrl.getProtocol())) { //$NON-NLS-1$ 201 File templateDirectory = new File(locationUrl.getFile()); 202 if (!templateDirectory.exists()) 203 return; 204 generateFiles(templateDirectory, fProject, true, false, monitor); 205 } 206 monitor.subTask(""); //$NON-NLS-1$ 207 monitor.worked(1); 208 } 209 generateFiles(File src, IContainer dst, boolean firstLevel, boolean binary, IProgressMonitor monitor)210 private void generateFiles(File src, IContainer dst, boolean firstLevel, boolean binary, IProgressMonitor monitor) throws CoreException { 211 File[] members = src.listFiles(); 212 213 for (File member : members) { 214 if (member.getName().equals("ext.xml") || //$NON-NLS-1$ 215 member.getName().equals("java") || //$NON-NLS-1$ 216 member.getName().equals("concept3.xhtml") || //$NON-NLS-1$ 217 member.getName().equals("extContent.xhtml")) //$NON-NLS-1$ 218 continue; 219 else if (member.isDirectory()) { 220 IContainer dstContainer = null; 221 if (firstLevel) { 222 binary = false; 223 if (member.getName().equals("bin")) { //$NON-NLS-1$ 224 binary = true; 225 dstContainer = dst; 226 } 227 } 228 if (dstContainer == null) { 229 dstContainer = dst.getFolder(new Path(member.getName())); 230 } 231 if (dstContainer instanceof IFolder && !dstContainer.exists()) 232 ((IFolder) dstContainer).create(true, true, monitor); 233 generateFiles(member, dstContainer, false, binary, monitor); 234 } else { 235 if (firstLevel) 236 binary = false; 237 try (InputStream in = new FileInputStream(member);) { 238 copyFile(member.getName(), in, dst, binary, monitor); 239 } catch (IOException ioe) { 240 } 241 } 242 } 243 } 244 copyFile(String fileName, InputStream input, IContainer dst, boolean binary, IProgressMonitor monitor)245 private void copyFile(String fileName, InputStream input, IContainer dst, boolean binary, IProgressMonitor monitor) throws CoreException { 246 247 monitor.subTask(fileName); 248 IFile dstFile = dst.getFile(new Path(fileName)); 249 250 try (InputStream stream = getProcessedStream(fileName, input, binary)) { 251 if (dstFile.exists()) { 252 dstFile.setContents(stream, true, true, monitor); 253 } else { 254 dstFile.create(stream, true, monitor); 255 } 256 } catch (IOException e) { 257 } 258 } 259 getProcessedStream(String fileName, InputStream stream, boolean binary)260 private InputStream getProcessedStream(String fileName, InputStream stream, boolean binary) throws IOException, CoreException { 261 if (binary) 262 return stream; 263 264 InputStreamReader reader = new InputStreamReader(stream); 265 int bufsize = 1024; 266 char[] cbuffer = new char[bufsize]; 267 int read = 0; 268 StringBuilder keyBuffer = new StringBuilder(); 269 StringBuilder outBuffer = new StringBuilder(); 270 ControlStack preStack = new ControlStack(); 271 preStack.setValueProvider(this); 272 273 boolean replacementMode = false; 274 while (read != -1) { 275 read = reader.read(cbuffer); 276 for (int i = 0; i < read; i++) { 277 char c = cbuffer[i]; 278 279 if (preStack.getCurrentState() == false) { 280 continue; 281 } 282 283 if (c == '$') { 284 if (replacementMode) { 285 replacementMode = false; 286 String key = keyBuffer.toString(); 287 String value = key.length() == 0 ? "$" //$NON-NLS-1$ 288 : getReplacementString(fileName, key); 289 outBuffer.append(value); 290 keyBuffer.delete(0, keyBuffer.length()); 291 } else { 292 replacementMode = true; 293 } 294 } else { 295 if (replacementMode) 296 keyBuffer.append(c); 297 else { 298 outBuffer.append(c); 299 } 300 } 301 } 302 } 303 return new ByteArrayInputStream(outBuffer.toString().getBytes(fProject.getDefaultCharset())); 304 } 305 getReplacementString(String fileName, String key)306 private String getReplacementString(String fileName, String key) { 307 if (key.equals(KEY_PRODUCT_NAME)) { 308 return fProduct.getName(); 309 } 310 return key; 311 } 312 313 @Override getValue(String variable)314 public Object getValue(String variable) { 315 return null; 316 } 317 } 318