Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 35ebc2dea906bc9a8f1ba1fb8e45a097965760e0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
/*******************************************************************************
 * Copyright (c) 2006 - 2012 CEA LIST.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA LIST - initial API and implementation
 *******************************************************************************/

package org.eclipse.papyrus.acceleo;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;

import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.util.EList;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Enumeration;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Namespace;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.PackageableElement;
import org.eclipse.uml2.uml.PrimitiveType;
import org.eclipse.uml2.uml.Relationship;
import org.eclipse.uml2.uml.Usage;


/**
 * Main class of code generator. This is an abstract class that is supposed to be overriden by language specific code generators
 */
abstract public class ModelElementsCreator {

	/**
	 * Creates the files corresponding to the class. For a "simple" class
	 * generates 2 headers (one for the privates concrete operations and one for
	 * the attributes, public operations and virtual / abstract operations and
	 * one body file.
	 * 
	 * @param folder
	 * @param classifier
	 * @throws CoreException
	 */
	abstract protected void createClassifierFiles(IContainer container, Classifier classifier) throws CoreException;

	/**
	 * Create the files for a package
	 * 
	 * @param packageContainer
	 * @param monitor
	 * @param pkg
	 * @throws CoreException
	 */
	abstract protected void createPackageFiles(IContainer packageContainer, IProgressMonitor monitor, Package pkg) throws CoreException;

	/**
	 * Boolean that returns whether a namespace is a root element. This function is currently not well supported, return false, if in doubt
	 * 
	 * @param ns
	 * @return
	 */
	abstract protected boolean isRoot(Namespace ns);

	/**
	 * Return true, if no code should be generated for a certain element
	 * 
	 * @param element
	 * @return
	 */
	abstract protected boolean noCodeGen(Element element);

	/**
	 * 
	 * Constructor.
	 * 
	 * @param project
	 *        the project in which the generated code should be placed
	 * @param headerComment
	 *        Prefix for each generated file
	 */
	public ModelElementsCreator(IProject project, String headerComment) {
		this.project = project;
		this.commentHeader = headerComment;
	}

	protected String commentHeader;

	protected IProject project;

	/**
	 * Main function for user calls. Creates code for a packageable element.
	 * 
	 * @param monitor
	 *        a progress monitor
	 * @param element
	 *        the element for which code should be generated
	 * @throws CoreException
	 */
	public void createPackageableElement(IProgressMonitor monitor, PackageableElement element) throws CoreException {
		IContainer packageContainer = getContainer(element);
		createPackageableElement(packageContainer, monitor, element);
	}

	/**
	 * Variant of main function: user may supply explicit container (also used by internal function to avoid
	 * re-calculating the entry container for each element).
	 * 
	 * @param packageContainer
	 *        The container (directory), in which code should be created
	 * @param monitor
	 *        a progress monitor
	 * @param element
	 *        the element for which code should be generated
	 * @throws CoreException
	 */
	public void createPackageableElement(IContainer packageContainer, IProgressMonitor monitor, PackageableElement element) throws CoreException {
		if(element instanceof Package) {
			createPackage(packageContainer, monitor, (Package)element);
		}
		else if((element instanceof PrimitiveType) || (element instanceof Enumeration) || (element instanceof Usage)) {
			// do nothing, included in package
		}
		else if(element instanceof Classifier) {
			createClassifierFiles(packageContainer, (Classifier)element);
		}
		else if(element instanceof Relationship) {
			// no code generation for relationships
		} else {
			throw new RuntimeException("C++ code generator: unsupported model element " + element); //$NON-NLS-1$
		}
	}


	/**
	 * Remove elements (used for differential code generation)
	 * 
	 * @param monitor
	 * @param element
	 * @throws CoreException
	 */
	public void removePackageableElement(IProgressMonitor monitor, PackageableElement element) throws CoreException {
		IContainer packageContainer = getContainer(element);
		if(packageContainer instanceof IFolder) {
			if(element instanceof Package) {
				IFolder folder = ((IFolder)packageContainer).getFolder(element.getName());
				folder.delete(true, null);
			} else if(element instanceof Classifier) {
				IFile file = ((IFolder)packageContainer).getFile(element.getName());
				file.delete(true, null);
			}
		}
	}

	/**
	 * Creates a <em>text</em> file in an eclipse container (either IFolder or
	 * IProject). If this file already exists it is replaced.
	 * 
	 * @param owner
	 *        the container that will contain the file.
	 * @param filename
	 *        The name of the file to create.
	 * @param content
	 *        Te text content of the file.
	 * @throws CoreException
	 */
	protected void createFile(IContainer owner, String filename, String content, boolean force) throws CoreException {
		IFile file = null;
		if(owner instanceof IProject) {
			file = ((IProject)owner).getFile(filename);
		} else if(owner instanceof IFolder) {
			file = ((IFolder)owner).getFile(filename);
		} else {
			// undefined
		}
		if(file != null) {
			createFile(file, content, force);
		}
	}

	/**
	 * Creates a <em>text</em> file in an eclipse folder. If this file already
	 * exists it is replaced.
	 * 
	 * @param folder
	 *        The folder that will contain the file.
	 * @param filename
	 *        The name of the file to create.
	 * @param content
	 *        Te text content of the file.
	 * @throws CoreException
	 */
	protected void createFile(IFile file, String content, boolean force) throws CoreException {
		if(file.exists() && force) {
			// file.delete(true,true,null);
			// YT - deleting files produce inconsistency in SVN working copies
			final URI locationURI = file.getLocationURI();
			if(locationURI != null) {
				IFileStore store = EFS.getStore(locationURI);
				OutputStream os = store.openOutputStream(0, null);
				try {
					os.write(content.getBytes());
				} catch (IOException e) {
					throw new RuntimeException ("C++ code generation: " + e.getMessage()); //$NON-NLS-1$
				}
			}
			// file.setContents(new ByteArrayInputStream(content.getBytes()),
			// true, true, null);
		} else if(file.exists() && !(force)) {
			// the file is not updated
		} else {
			// the file does not exists
			file.create(new ByteArrayInputStream(content.getBytes()), true, null);
		}
	}

	/**
	 * Recursively creates folders for a given package
	 * 
	 * @param packageContainer
	 *        The folder where the folder hierarchy for this package will be
	 *        created.
	 * @param monitor
	 *        a progress monitor
	 * @param pkg
	 *        the package for which code should be created
	 * @throws CoreException
	 */
	protected void createPackage(IContainer packageContainer, IProgressMonitor monitor, Package pkg) throws CoreException {
		monitor.subTask("generate package " + pkg.getQualifiedName()); //$NON-NLS-1$

		if(!isRoot(pkg) && !noCodeGen(pkg)) {

			packageContainer = (packageContainer instanceof IProject) ? ((IProject)packageContainer).getFolder(pkg.getName()) : ((IFolder)packageContainer).getFolder(pkg.getName());

			// Create a new folder corresponding to the package if it does not exist
			if(!packageContainer.exists()) {
				// if packageContainer is a Project, it necessarily exists
				((IFolder)packageContainer).create(false, true, null);
			}

			createPackageFiles(packageContainer, monitor, pkg);

			// Continue generation parsing package content
			// If CppNoCodeGen on package, it applies to its content

			for(PackageableElement currentElement : pkg.getPackagedElements()) {
				createPackageableElement(packageContainer, monitor, currentElement);
			}
		}
	}

	/**
	 * Return a container (folder) for a given named element. The folder is embedded into a set
	 * of folders that correspond to the namespaces of the element. These folders will be
	 * created, if the do not exist (comparable to "mkdir -p" in Unix).
	 * 
	 * @param element
	 *        a named element
	 * @return folder for this element
	 */
	public IContainer getContainer(NamedElement element) {
		try {
			IContainer packageContainer = project;
			EList<Namespace> namespaces = element.allNamespaces();
			for(int i = namespaces.size() - 1; i >= 0; i--) {
				Namespace ns = namespaces.get(i);
				if(isRoot(ns)) {
					// TODO: not very clean. Is this stereotype still used?
					packageContainer = project;
				} else if(packageContainer instanceof IFolder) {
					packageContainer = ((IFolder)packageContainer).getFolder(ns.getName());
				} else if(packageContainer instanceof IProject) {
					packageContainer = ((IProject)packageContainer).getFolder(ns.getName());
				}
				if(!packageContainer.exists()) {
					// if packageContainer is a Project, it necessarily exists
					((IFolder)packageContainer).create(false, true, null);
				}
			}
			return packageContainer;
		} catch (CoreException e) {
			e.printStackTrace();
			return null;
		}
	}
}

Back to the top