KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > pde > internal > ui > editor > contentassist > XMLInsertionComputer


1 /*******************************************************************************
2  * Copyright (c) 2006, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11
12 package org.eclipse.pde.internal.ui.editor.contentassist;
13
14 import java.util.HashSet JavaDoc;
15
16 import org.eclipse.core.resources.IProject;
17 import org.eclipse.core.resources.IResource;
18 import org.eclipse.core.runtime.CoreException;
19 import org.eclipse.osgi.util.NLS;
20 import org.eclipse.pde.core.IBaseModel;
21 import org.eclipse.pde.core.IIdentifiable;
22 import org.eclipse.pde.core.IModel;
23 import org.eclipse.pde.core.plugin.IPluginElement;
24 import org.eclipse.pde.core.plugin.IPluginExtension;
25 import org.eclipse.pde.core.plugin.IPluginObject;
26 import org.eclipse.pde.core.plugin.IPluginParent;
27 import org.eclipse.pde.internal.core.ischema.IMetaAttribute;
28 import org.eclipse.pde.internal.core.ischema.ISchemaAttribute;
29 import org.eclipse.pde.internal.core.ischema.ISchemaComplexType;
30 import org.eclipse.pde.internal.core.ischema.ISchemaCompositor;
31 import org.eclipse.pde.internal.core.ischema.ISchemaElement;
32 import org.eclipse.pde.internal.core.ischema.ISchemaObject;
33 import org.eclipse.pde.internal.core.ischema.ISchemaRestriction;
34 import org.eclipse.pde.internal.core.ischema.ISchemaRootElement;
35 import org.eclipse.pde.internal.core.ischema.ISchemaSimpleType;
36 import org.eclipse.pde.internal.core.ischema.ISchemaType;
37 import org.eclipse.pde.internal.core.schema.SchemaAttribute;
38 import org.eclipse.pde.internal.ui.PDEPlugin;
39 import org.eclipse.pde.internal.ui.PDEUIMessages;
40 import org.eclipse.pde.internal.ui.editor.text.XMLUtil;
41
42 /**
43  * XMLInsertionComputer
44  *
45  */

46 public class XMLInsertionComputer {
47
48     /**
49      * @param sElement
50      * @param pElement
51      */

52     public static void computeInsertion(ISchemaElement sElement,
53             IPluginParent pElement) {
54         HashSet JavaDoc visited = new HashSet JavaDoc();
55         if ((sElement == null) ||
56                 (pElement == null)) {
57             // If there is no corresponding schema information or plug-in
58
// model, then there is nothing to augment
59
return;
60         }
61         visited.add(sElement.getName());
62         // Process the parent element or extension
63
try {
64             computeInsertionParent(sElement, pElement, visited);
65         } catch (CoreException e) {
66             // All exceptions bubble up to this point
67
PDEPlugin.logException(e);
68         }
69     }
70     
71     /**
72      * @param sElement
73      * @param pElement
74      * @param visited
75      * @throws CoreException
76      */

77     protected static void computeInsertionParent(ISchemaElement sElement,
78             IPluginParent pElement, HashSet JavaDoc visited) throws CoreException {
79         // Determine if the edge case is applicable
80
if (isSingleZeroElementEdgeCase(sElement, pElement)) {
81             // Process the edge case
82
computeInsertionZeroElementEdgeCase(sElement, pElement, visited);
83         } else {
84             // Process the normal case
85
computeInsertionType(sElement, pElement, visited);
86         }
87     }
88     
89     /**
90      * Edge Case:
91      * Extension element has a sequence compositor containing one child element
92      * whose min occurs is 0.
93      * This is an extension point schema bug. However, to mask this bug and make
94      * life easier for the user, interpret the child element min occurs as 1;
95      * since, it makes no sense for an extension not to have any child elements
96      * In essence, we auto-generate the child element when none should have
97      * been.
98      * See Bug # 162379 for details.
99      * @param sElement
100      * @param pElement
101      * @param visited
102      * @throws CoreException
103      */

104     protected static void computeInsertionZeroElementEdgeCase(
105             ISchemaElement sElement, IPluginParent pElement, HashSet JavaDoc visited)
106             throws CoreException {
107         // We can make a variety of assumptions because of the single zero
108
// element edge case check
109
// We know we have a schema complex type
110
// Insert the extension attributes
111
computeInsertionAllAttributes(pElement, sElement);
112         // Get the extension compositor
113
ISchemaCompositor compositor =
114             ((ISchemaComplexType)sElement.getType()).getCompositor();
115         // We know that there is only one child that is an element with a
116
// min occurs of 0
117
ISchemaElement childSchemaElement =
118             (ISchemaElement)compositor.getChildren()[0];
119         // Process the element as if the min occurs was 1
120
// Create the element
121
IPluginElement childElement = createElement(pElement, childSchemaElement);
122         // Track visited
123
visited.add(childSchemaElement.getName());
124         // Revert back to the normal process
125
computeInsertionType(childSchemaElement, childElement, visited);
126         // Add the new child element to the parent after its own child
127
// elements and attributes have been recursively added
128
pElement.add(childElement);
129     }
130         
131     /**
132      * @param sElement
133      * @param pElement
134      * @return
135      */

136     protected static boolean isSingleZeroElementEdgeCase(ISchemaElement sElement,
137             IPluginParent pElement) {
138         // Determine whether the edge case is applicable
139
if ((sElement.getType() instanceof ISchemaComplexType) &&
140                 (pElement instanceof IPluginExtension)) {
141             // We have an extension
142
// Get the extension's compositor
143
ISchemaCompositor compositor =
144                 ((ISchemaComplexType)sElement.getType()).getCompositor();
145             // Determine if the compositor is a sequence compositor with one
146
// child and a min occurs of one
147
if ((compositor == null) ||
148                     (isSequenceCompositor(compositor) == false) ||
149                     (compositor.getChildCount() != 1) ||
150                     (compositor.getMinOccurs() != 1)) {
151                 return false;
152             }
153             // We have a non-null sequence compositor that has one child and
154
// a min occurs of 1
155
// Get the compositor's one child
156
ISchemaObject schemaObject = compositor.getChildren()[0];
157             // Determine if the child is an element
158
if ((schemaObject instanceof ISchemaElement) == false) {
159                 return false;
160             }
161             // We have a child element
162
ISchemaElement schemaElement = (ISchemaElement)schemaObject;
163             // Determine if the child element has a min occurs of 0
164
if (schemaElement.getMinOccurs() == 0) {
165                 return true;
166             }
167         }
168         return false;
169     }
170
171     /**
172      * @param sElement
173      * @param pElement
174      * @param visited
175      * @throws CoreException
176      */

177     protected static void computeInsertionType(ISchemaElement sElement,
178             IPluginParent pElement, HashSet JavaDoc visited) throws CoreException {
179         
180         if ((sElement == null) ||
181                 (pElement == null)) {
182             // If there is no corresponding schema information or plug-in
183
// model, then there is nothing to augment
184
return;
185         } else if (sElement.getType() instanceof ISchemaSimpleType) {
186             // For simple types, insert a comment informing the user to
187
// add element content text
188
try {
189                 if (pElement instanceof IPluginElement)
190                     ((IPluginElement)pElement).setText(NLS.bind(
191                             PDEUIMessages.XMLCompletionProposal_InfoElement,
192                             pElement.getName()));
193             } catch (CoreException e) {
194                 PDEPlugin.logException(e);
195             }
196             return;
197         } else if (sElement.getType() instanceof ISchemaComplexType) {
198             // Note: Mixed content types do not affect auto-generation
199
// Note: Deprecated elements do not affect auto-generation
200
// Insert element attributes
201
computeInsertionAllAttributes(pElement, sElement);
202             // Get this element's compositor
203
ISchemaCompositor compositor =
204                 ((ISchemaComplexType)sElement.getType()).getCompositor();
205             // Process the compositor
206
computeInsertionSequence(compositor, pElement, visited);
207         } else {
208             // Unknown element type
209
return;
210         }
211     }
212
213     /**
214      * @param pElement
215      * @param visited
216      * @param schemaObject
217      * @throws CoreException
218      */

219     protected static void computeInsertionObject(IPluginParent pElement,
220             HashSet JavaDoc visited, ISchemaObject schemaObject) throws CoreException {
221         if (schemaObject instanceof ISchemaElement) {
222             ISchemaElement schemaElement = (ISchemaElement) schemaObject;
223             computeInsertionElement(pElement, visited, schemaElement);
224         } else if (schemaObject instanceof ISchemaCompositor) {
225             ISchemaCompositor sCompositor = (ISchemaCompositor) schemaObject;
226             computeInsertionSequence(sCompositor, pElement, visited);
227         } else {
228             // Unknown schema object
229
}
230     }
231
232     /**
233      * @param pElement
234      * @param compositor
235      */

236     protected static boolean isSequenceCompositor(ISchemaCompositor compositor) {
237         if (compositor == null) {
238             return false;
239         } else if (compositor.getKind() == ISchemaCompositor.CHOICE) {
240             // Too presumption to choose for the user
241
// Avoid processing and generate a comment to inform the user that
242
// they need to update this element accordingly
243
return false;
244         } else if (compositor.getKind() == ISchemaCompositor.ALL) {
245             // Not supported by PDE - should never get here
246
return false;
247         } else if (compositor.getKind() == ISchemaCompositor.GROUP) {
248             // Not supported by PDE - should never get here
249
return false;
250         } else if (compositor.getKind() == ISchemaCompositor.SEQUENCE) {
251             return true;
252         } else {
253             // Unknown compositor
254
return false;
255         }
256     }
257
258     /**
259      * @param pElement
260      * @param visited
261      * @param schemaElement
262      * @throws CoreException
263      */

264     protected static void computeInsertionElement(IPluginParent pElement,
265             HashSet JavaDoc visited, ISchemaElement schemaElement) throws CoreException {
266         for (int j = 0; j < schemaElement.getMinOccurs(); j++) {
267             // Update Model
268
IPluginElement childElement = createElement(pElement, schemaElement);
269             // Track visited
270
HashSet JavaDoc newSet = (HashSet JavaDoc) visited.clone();
271             if (newSet.add(schemaElement.getName())) {
272                 computeInsertionType(schemaElement, childElement, newSet);
273             } else {
274                 childElement.setText(
275                         PDEUIMessages.XMLCompletionProposal_ErrorCycle);
276             }
277             // Add the new child element to the parent after its own child
278
// elements and attributes have been recursively added
279
pElement.add(childElement);
280         }
281     }
282
283     /**
284      * Important: Element is created but not added as a child to the plug-in
285      * parent. Callers responsibility to add the child element to the parent.
286      * @param pElement
287      * @param schemaElement
288      * @return
289      * @throws CoreException
290      */

291     protected static IPluginElement createElement(IPluginParent pElement,
292             ISchemaElement schemaElement) throws CoreException {
293         IPluginElement childElement = null;
294         childElement =
295             pElement.getModel().getFactory().createElement(pElement);
296         childElement.setName(schemaElement.getName());
297         return childElement;
298     }
299
300     /**
301      * @param pElement
302      * @param type
303      * @param attributes
304      */

305     protected static void computeInsertionAllAttributes(IPluginParent pElement,
306             ISchemaElement sElement) {
307         // Has to be a complex type if there are attributes
308
ISchemaComplexType type = (ISchemaComplexType)sElement.getType();
309         // Get the underlying project
310
IResource resource = pElement.getModel().getUnderlyingResource();
311         IProject project = null;
312         if (resource != null)
313             project = resource.getProject();
314         // Get all the attributes
315
ISchemaAttribute[] attributes = type.getAttributes();
316         // Generate a unique number for IDs
317
int counter = XMLUtil.getCounterValue(sElement);
318         // Process all attributes
319
for (int i = 0; i < type.getAttributeCount(); i++) {
320             ISchemaAttribute attribute = attributes[i];
321             // Note: If an attribute is deprecated, it does not affect
322
// auto-generation.
323
try {
324                 if (attribute.getUse() == ISchemaAttribute.REQUIRED) {
325                     String JavaDoc value = generateAttributeValue(project, counter, attribute);
326                     // Update Model
327
setAttribute(pElement, attribute.getName(), value, counter);
328                 }
329                 // Ignore optional attributes
330
} catch (CoreException e) {
331                 PDEPlugin.logException(e);
332             }
333         }
334     }
335
336     /**
337      * @param project
338      * @param counter
339      * @param attribute
340      * @return
341      */

342     protected static String JavaDoc generateAttributeValue(IProject project,
343             int counter, ISchemaAttribute attribute) {
344         String JavaDoc value = ""; //$NON-NLS-1$
345
ISchemaRestriction restriction =
346             attribute.getType().getRestriction();
347
348         if (attribute.getKind() == IMetaAttribute.JAVA &&
349             project != null) {
350             // JAVA
351
value = XMLUtil.createDefaultClassName(project,
352                     attribute, counter);
353         } else if (restriction != null) {
354             // STRING &&
355
// RESTRICTION
356
// Check for enumeration restrictions, if there is one,
357
// just pick the first enumerated value
358
value = restriction.getChildren()[0].toString();
359         } else if ((attribute instanceof SchemaAttribute) &&
360                     ((SchemaAttribute)attribute).isTranslatable()) {
361             // STRING &&
362
// TRANSLATABLE
363
value = attribute.getName();
364         } else if (project != null) {
365             // STRING ||
366
// RESOURCE
367
value = XMLUtil.createDefaultName(project,
368                     attribute, counter);
369         }
370         return value;
371     }
372     
373     public static String JavaDoc generateAttributeValue(ISchemaAttribute attribute,
374             IBaseModel baseModel, String JavaDoc defaultValue) {
375         if (baseModel instanceof IModel) {
376             IResource resource = ((IModel)baseModel).getUnderlyingResource();
377             if (resource != null) {
378                 int counter = 1;
379                 if (attribute.getParent() instanceof ISchemaElement) {
380                     ISchemaElement sElement = (ISchemaElement)attribute.getParent();
381                     if (sElement instanceof ISchemaRootElement) {
382                         // The parent element is either a extension or an
383
// extension-point
384
// Do not auto-generate attribute values for those
385
// elements
386
return defaultValue;
387                     }
388                     // Generate a unique number for IDs
389
counter = XMLUtil.getCounterValue(sElement);
390                 }
391                 return generateAttributeValue(resource.getProject(), counter, attribute);
392             }
393         }
394         return defaultValue;
395     }
396     
397     /**
398      * @param compositor
399      * @param pElement
400      * @param visited
401      */

402     protected static void computeInsertionSequence(ISchemaCompositor compositor,
403             IPluginParent pElement, HashSet JavaDoc visited) throws CoreException {
404         if (compositor == null)
405             return;
406         // Process the compositor the minimum number of times
407
for (int k = 0; k < compositor.getMinOccurs(); k++) {
408             // Only continue processing if the compositor is a sequence
409
if (isSequenceCompositor(compositor) == false)
410                 continue;
411             // We have a sequence
412
ISchemaObject[] schemaObject = compositor.getChildren();
413             // Process the compositors children
414
for (int i = 0; i < compositor.getChildCount(); i++) {
415                 computeInsertionObject(pElement, visited, schemaObject[i]);
416             }
417         }
418     }
419
420     /**
421      * @param parent
422      * @param attName
423      * @param attValue
424      * @param counter
425      * @throws CoreException
426      */

427     protected static void setAttribute(IPluginParent parent, String JavaDoc attName,
428             String JavaDoc attValue, int counter) throws CoreException {
429         if (parent instanceof IPluginElement) {
430             ((IPluginElement)parent).setAttribute(attName, attValue);
431         } else if (parent instanceof IPluginExtension) {
432             IPluginExtension pe = (IPluginExtension)parent;
433             if (attName.equals(IIdentifiable.P_ID)) {
434                 String JavaDoc currValue = pe.getId();
435                 // If a value was already defined, do not override it with the
436
// auto-generated value
437
if (currValue == null || currValue.length() == 0) {
438                     // Ignore the auto-generated attribute value and use the
439
// attribute name
440
pe.setId(attName + counter);
441                 }
442             } else if (attName.equals(IPluginObject.P_NAME)) {
443                 String JavaDoc currValue = pe.getName();
444                 if (currValue == null || currValue.length() == 0)
445                     pe.setName(attName);
446             } else if (attName.equals(IPluginExtension.P_POINT)) {
447                 String JavaDoc currValue = pe.getPoint();
448                 if (currValue == null || currValue.length() == 0)
449                     pe.setPoint(attValue);
450             }
451         }
452     }
453
454     public static boolean hasOptionalAttributes(ISchemaElement ele) {
455         ISchemaAttribute[] attrs = ele.getAttributes();
456         for (int i = 0; i < attrs.length; i++)
457             if (attrs[i].getUse() == ISchemaAttribute.OPTIONAL ||
458                     attrs[i].getUse() == ISchemaAttribute.DEFAULT)
459                 return true;
460         return false;
461     }
462
463     public static boolean hasOptionalChildren(ISchemaObject obj, boolean onChild, HashSet JavaDoc set) {
464         if (obj == null || set.contains(obj))
465             return false;
466         set.add(obj);
467         if (obj instanceof ISchemaElement) {
468             if (onChild
469                     && ((ISchemaElement)obj).getMinOccurs() == 0
470                     && ((ISchemaElement)obj).getMaxOccurs() > 0)
471                 return true;
472             ISchemaType type = ((ISchemaElement) obj).getType();
473             if (type instanceof ISchemaComplexType)
474                 return hasOptionalChildren(((ISchemaComplexType)type).getCompositor(), true, set);
475         } else if (obj instanceof ISchemaCompositor) {
476             ISchemaObject[] children = ((ISchemaCompositor)obj).getChildren();
477             if (children != null)
478                 for (int i = 0; i < children.length; i++)
479                     if (hasOptionalChildren(children[i], true, set))
480                         return true;
481         }
482         return false;
483     }
484     
485 }
486
Popular Tags