Package: EObjectServices$EObjectFeatureAccess

EObjectServices$EObjectFeatureAccess

nameinstructionbranchcomplexitylinemethod
EObjectServices.EObjectFeatureAccess(Method, Object)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
featureAccessTypes(ValidationServices, IReadOnlyQueryEnvironment, IType, String)
M: 146 C: 0
0%
M: 18 C: 0
0%
M: 10 C: 0
0%
M: 29 C: 0
0%
M: 1 C: 0
0%
getEStructuralFeatureProposals(IReadOnlyQueryEnvironment, Set)
M: 52 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 9 C: 0
0%
M: 1 C: 0
0%
getProposals(IReadOnlyQueryEnvironment, Set)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getType(Call, ValidationServices, IValidationResult, IReadOnlyQueryEnvironment, List)
M: 19 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
validateAllType(ValidationServices, IReadOnlyQueryEnvironment, Map)
M: 37 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*******************************************************************************
2: * Copyright (c) 2015 Obeo.
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: * Obeo - initial API and implementation
10: *******************************************************************************/
11: package org.eclipse.acceleo.query.services;
12:
13: import com.google.common.collect.Iterables;
14: import com.google.common.collect.Lists;
15: import com.google.common.collect.Sets;
16:
17: import java.lang.reflect.Method;
18: import java.util.ArrayList;
19: import java.util.Collection;
20: import java.util.Collections;
21: import java.util.Iterator;
22: import java.util.LinkedHashSet;
23: import java.util.List;
24: import java.util.Map;
25: import java.util.Map.Entry;
26: import java.util.Set;
27:
28: import org.eclipse.acceleo.annotations.api.documentation.Documentation;
29: import org.eclipse.acceleo.annotations.api.documentation.Example;
30: import org.eclipse.acceleo.annotations.api.documentation.Param;
31: import org.eclipse.acceleo.annotations.api.documentation.ServiceProvider;
32: import org.eclipse.acceleo.query.ast.Call;
33: import org.eclipse.acceleo.query.ast.StringLiteral;
34: import org.eclipse.acceleo.query.parser.AstBuilderListener;
35: import org.eclipse.acceleo.query.runtime.AcceleoQueryEvaluationException;
36: import org.eclipse.acceleo.query.runtime.CrossReferenceProvider;
37: import org.eclipse.acceleo.query.runtime.ICompletionProposal;
38: import org.eclipse.acceleo.query.runtime.IReadOnlyQueryEnvironment;
39: import org.eclipse.acceleo.query.runtime.IRootEObjectProvider;
40: import org.eclipse.acceleo.query.runtime.IService;
41: import org.eclipse.acceleo.query.runtime.IValidationResult;
42: import org.eclipse.acceleo.query.runtime.impl.AbstractServiceProvider;
43: import org.eclipse.acceleo.query.runtime.impl.JavaMethodService;
44: import org.eclipse.acceleo.query.runtime.impl.ValidationServices;
45: import org.eclipse.acceleo.query.runtime.impl.completion.EFeatureCompletionProposal;
46: import org.eclipse.acceleo.query.validation.type.ClassType;
47: import org.eclipse.acceleo.query.validation.type.EClassifierLiteralType;
48: import org.eclipse.acceleo.query.validation.type.EClassifierSetLiteralType;
49: import org.eclipse.acceleo.query.validation.type.EClassifierType;
50: import org.eclipse.acceleo.query.validation.type.IType;
51: import org.eclipse.acceleo.query.validation.type.SequenceType;
52: import org.eclipse.acceleo.query.validation.type.SetType;
53: import org.eclipse.emf.common.util.AbstractTreeIterator;
54: import org.eclipse.emf.common.util.BasicEMap;
55: import org.eclipse.emf.common.util.EMap;
56: import org.eclipse.emf.ecore.EClass;
57: import org.eclipse.emf.ecore.EClassifier;
58: import org.eclipse.emf.ecore.EObject;
59: import org.eclipse.emf.ecore.EReference;
60: import org.eclipse.emf.ecore.EStructuralFeature;
61: import org.eclipse.emf.ecore.EcorePackage;
62: import org.eclipse.emf.ecore.impl.EClassImpl;
63:
64: //@formatter:off
65: @ServiceProvider(
66:         value = "Services available for EObjects"
67: )
68: //@formatter:on
69: @SuppressWarnings({"checkstyle:javadocmethod", "checkstyle:javadoctype" })
70: public class EObjectServices extends AbstractServiceProvider {
71:
72:         /**
73:          * {@link EClass} containment message.
74:          */
75:         private static final String ONLY_E_CLASS_CAN_BE_CONTAINED_INTO_OTHER_E_CLASSES_NOT_S = "Only EClass can be contained into other EClasses not %s";
76:
77:         /**
78:          * Can't contain directly or indirectly message.
79:          */
80:         private static final String S_CAN_T_CONTAIN_DIRECTLY_OR_INDIRECTLY_S = "%s can't contain directly or indirectly %s";
81:
82:         /**
83:          * Log message used when accessing an unknown feature.
84:          */
85:         private static final String UNKNOWN_FEATURE = "Feature %s not found in EClass %s";
86:
87:         /**
88:          * Log message used when accessing a feature on a JavaObject.
89:          */
90:         private static final String NON_EOBJECT_FEATURE_ACCESS = "Attempt to access feature (%s) on a non ModelObject value (%s).";
91:
92:         /**
93:          * Illegal state message.
94:          */
95:         private static final String DON_T_KNOW_WHAT_TO_DO_WITH = "don't know what to do with ";
96:
97:         /**
98:          * Filtered eAllContents {@link Iterator}.
99:          *
100:          * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a>
101:          */
102:         private static final class FilteredContentIterator extends AbstractTreeIterator<EObject> {
103:
104:                 /**
105:                  * Generated serial version UID.
106:                  */
107:                 private static final long serialVersionUID = -1537663884310088034L;
108:
109:                 /**
110:                  * The {@link Set} of {@link EStructuralFeature} to navigate.
111:                  */
112:                 private final Set<EStructuralFeature> features;
113:
114:                 /**
115:                  * Constructor.
116:                  *
117:                  * @param object
118:                  * the root object
119:                  * @param includeRoot
120:                  * <code>true</code> to include root, <code>false</code> otherwise
121:                  * @param features
122:                  * the {@link Set} of {@link EStructuralFeature} to navigate
123:                  */
124:                 private FilteredContentIterator(Object object, boolean includeRoot, Set<EStructuralFeature> features) {
125:                         super(object, includeRoot);
126:                         this.features = features;
127:                 }
128:
129:                 @Override
130:                 public Iterator<EObject> getChildren(Object object) {
131:                         final List<EObject> result = Lists.newArrayList();
132:                         if (object instanceof EObject) {
133:                                 EObject host = (EObject)object;
134:                                 EStructuralFeature[] eStructuralFeatures = ((EClassImpl.FeatureSubsetSupplier)host.eClass()
135:                                                 .getEAllStructuralFeatures()).containments();
136:                                 if (eStructuralFeatures != null) {
137:                                         for (EStructuralFeature feat : eStructuralFeatures) {
138:                                                 if (features.contains(feat)) {
139:                                                         addChildren(result, host, feat);
140:                                                 }
141:                                         }
142:                                 }
143:
144:                         }
145:                         return result.iterator();
146:                 }
147:
148:                 /**
149:                  * Add the children of the given {@link EObject} and the given {@link EStructuralFeature}.
150:                  *
151:                  * @param result
152:                  * the
153:                  * @param eObject
154:                  * @param feature
155:                  */
156:                 private void addChildren(final List<EObject> result, EObject eObject, EStructuralFeature feature) {
157:                         Object value = eObject.eGet(feature);
158:                         if (feature.isMany()) {
159:                                 if (value instanceof Collection<?>) {
160:                                         for (EObject childElement : Iterables.filter((Collection<?>)value, EObject.class)) {
161:                                                 result.add(childElement);
162:                                         }
163:                                 } else {
164:                                         throw new IllegalStateException(DON_T_KNOW_WHAT_TO_DO_WITH + value.getClass());
165:                                 }
166:                         } else if (value instanceof EObject) {
167:                                 result.add((EObject)value);
168:
169:                         }
170:                 }
171:         }
172:
173:         private static final class EObjectFeatureAccess extends JavaMethodService {
174:
175:                 /**
176:                  * Creates a new service instance given a method and an instance.
177:                  *
178:                  * @param method
179:                  * the method that realizes the service
180:                  * @param serviceInstance
181:                  * the instance on which the service must be called
182:                  */
183:                 public EObjectFeatureAccess(Method method, Object serviceInstance) {
184:                         super(method, serviceInstance);
185:                 }
186:
187:                 /**
188:                  * {@inheritDoc}
189:                  *
190:                  * @see org.eclipse.acceleo.query.runtime.impl.JavaMethodService#getType(org.eclipse.acceleo.query.ast.Call,
191:                  * org.eclipse.acceleo.query.runtime.impl.ValidationServices,
192:                  * org.eclipse.acceleo.query.runtime.IValidationResult,
193:                  * org.eclipse.acceleo.query.runtime.IReadOnlyQueryEnvironment, java.util.List)
194:                  */
195:                 @Override
196:                 public Set<IType> getType(Call call, ValidationServices services, IValidationResult validationResult,
197:                                 IReadOnlyQueryEnvironment queryEnvironment, List<IType> argTypes) {
198:                         final String featureName = ((StringLiteral)call.getArguments().get(1)).getValue();
199:                         final Set<IType> result = featureAccessTypes(services, queryEnvironment, argTypes.get(0),
200:                                         featureName);
201:
202:                         return result;
203:                 }
204:
205:                 /**
206:                  * Gets the type of a feature access.
207:                  *
208:                  * @param queryEnvironment
209:                  * the {@link IReadOnlyQueryEnvironment}
210:                  * @param receiverTypes
211:                  * the target types to gets the feature from
212:                  * @param featureName
213:                  * the feature name
214:                  * @return the type of a feature access
215:                  */
216:                 public Set<IType> featureAccessTypes(ValidationServices services,
217:                                 IReadOnlyQueryEnvironment queryEnvironment, IType receiverType, String featureName) {
218:                         final Set<IType> result = new LinkedHashSet<IType>();
219:
220:                         final Set<EClass> receiverEClasses = new LinkedHashSet<EClass>();
221:•                        if (receiverType.getType() instanceof EClass) {
222:                                 receiverEClasses.add((EClass)receiverType.getType());
223:•                        } else if (receiverType.getType() instanceof Class) {
224:                                 final Set<EClassifier> eClassifiers = queryEnvironment.getEPackageProvider().getEClassifiers(
225:                                                 (Class<?>)receiverType.getType());
226:•                                if (eClassifiers != null) {
227:•                                        for (EClassifier eCls : eClassifiers) {
228:•                                                if (eCls instanceof EClass) {
229:                                                         receiverEClasses.add((EClass)eCls);
230:                                                 }
231:                                         }
232:                                 }
233:                         } else {
234:                                 throw new IllegalStateException(DON_T_KNOW_WHAT_TO_DO_WITH + receiverType.getType());
235:                         }
236:
237:•                        if (receiverEClasses.isEmpty()) {
238:                                 result.add(services.nothing(NON_EOBJECT_FEATURE_ACCESS, featureName, receiverType.getType()
239:                                                 .toString()));
240:                         } else {
241:•                                for (EClass eClass : receiverEClasses) {
242:                                         EStructuralFeature feature = eClass.getEStructuralFeature(featureName);
243:•                                        if (feature == null) {
244:                                                 result.add(services.nothing(UNKNOWN_FEATURE, featureName, eClass.getName()));
245:                                         } else {
246:                                                 final EClassifierType featureBasicType = new EClassifierType(queryEnvironment,
247:                                                                 feature.getEType());
248:•                                                if (feature.isMany()) {
249:                                                         result.add(new SequenceType(queryEnvironment, featureBasicType));
250:                                                 } else {
251:                                                         result.add(featureBasicType);
252:                                                 }
253:                                         }
254:                                 }
255:                         }
256:
257:                         return result;
258:                         // CHECKSTYLE:OFF
259:                 }
260:
261:                 /**
262:                  * {@inheritDoc}
263:                  *
264:                  * @see org.eclipse.acceleo.query.runtime.impl.AbstractService#validateAllType(org.eclipse.acceleo.query.runtime.impl.ValidationServices,
265:                  * org.eclipse.acceleo.query.runtime.IReadOnlyQueryEnvironment, java.util.Map)
266:                  */
267:                 @Override
268:                 public Set<IType> validateAllType(ValidationServices services,
269:                                 IReadOnlyQueryEnvironment queryEnvironment, Map<List<IType>, Set<IType>> allTypes) {
270:                         final Set<IType> result = new LinkedHashSet<IType>();
271:
272:                         final Set<IType> knownReceiverTypes = new LinkedHashSet<IType>();
273:•                        for (Entry<List<IType>, Set<IType>> entry : allTypes.entrySet()) {
274:•                                if (knownReceiverTypes.add(entry.getKey().get(0))) {
275:                                         result.addAll(entry.getValue());
276:                                 }
277:                         }
278:
279:                         return result;
280:                 }
281:
282:                 @Override
283:                 public List<ICompletionProposal> getProposals(IReadOnlyQueryEnvironment queryEnvironment,
284:                                 Set<IType> receiverTypes) {
285:                         return getEStructuralFeatureProposals(queryEnvironment, receiverTypes);
286:                 }
287:
288:                 /**
289:                  * Gets the {@link List} of {@link EFeatureCompletionProposal} for {@link EStructuralFeature}.
290:                  *
291:                  * @param receiverTypes
292:                  * the receiver types.
293:                  * @return the {@link List} of {@link EFeatureCompletionProposal} for {@link EStructuralFeature}
294:                  */
295:                 public List<ICompletionProposal> getEStructuralFeatureProposals(
296:                                 IReadOnlyQueryEnvironment queryEnvironment, Set<IType> receiverTypes) {
297:                         final List<ICompletionProposal> result = new ArrayList<ICompletionProposal>();
298:                         final Set<EClass> eClasses = new LinkedHashSet<EClass>();
299:
300:•                        for (IType iType : receiverTypes) {
301:•                                if (iType.getType() instanceof EClass) {
302:                                         eClasses.add((EClass)iType.getType());
303:                                 }
304:                         }
305:
306:•                        for (EStructuralFeature feature : queryEnvironment.getEPackageProvider().getEStructuralFeatures(
307:                                         eClasses)) {
308:                                 result.add(new EFeatureCompletionProposal(feature));
309:                         }
310:
311:                         return result;
312:                 }
313:
314:         }
315:
316:         /**
317:          * EContainer {@link IService}.
318:          *
319:          * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a>
320:          */
321:         private static final class EContainerService extends FilterService {
322:
323:                 /**
324:                  * Creates a new service instance given a method and an instance.
325:                  *
326:                  * @param serviceMethod
327:                  * the method that realizes the service
328:                  * @param serviceInstance
329:                  * the instance on which the service must be called
330:                  */
331:                 private EContainerService(Method serviceMethod, Object serviceInstance) {
332:                         super(serviceMethod, serviceInstance);
333:                 }
334:
335:                 @Override
336:                 public Set<IType> getType(Call call, ValidationServices services, IValidationResult validationResult,
337:                                 IReadOnlyQueryEnvironment queryEnvironment, List<IType> argTypes) {
338:                         final Set<IType> result = new LinkedHashSet<IType>();
339:
340:                         if (argTypes.get(0).getType() instanceof EClass) {
341:                                 final EClass eCls = (EClass)argTypes.get(0).getType();
342:                                 if (eCls == EcorePackage.eINSTANCE.getEObject()) {
343:                                         if (argTypes.size() == 1) {
344:                                                 result.add(argTypes.get(0));
345:                                         } else if (argTypes.size() == 2) {
346:                                                 result.add(new EClassifierType(queryEnvironment, ((EClassifierLiteralType)argTypes
347:                                                                 .get(1)).getType()));
348:                                         }
349:                                 } else {
350:                                         result.addAll(getTypeForSpecificType(services, queryEnvironment, argTypes, eCls));
351:                                 }
352:                         } else {
353:                                 result.add(services.nothing(ONLY_E_CLASS_CAN_BE_CONTAINED_INTO_OTHER_E_CLASSES_NOT_S,
354:                                                 argTypes.get(0)));
355:                         }
356:
357:                         return result;
358:                 }
359:
360:                 /**
361:                  * Gets the {@link IType} of elements returned by the service when the receiver type is not the
362:                  * {@link EObject} {@link EClass}.
363:                  *
364:                  * @param services
365:                  * the {@link ValidationServices}
366:                  * @param queryEnvironment
367:                  * the {@link IReadOnlyQueryEnvironment}
368:                  * @param argTypes
369:                  * arguments {@link IType}
370:                  * @param receiverEClass
371:                  * the receiver type can't be {@link EObject} {@link EClass}
372:                  * @return the {@link IType} of elements returned by the service when the receiver type is not the
373:                  * {@link EObject} {@link EClass}
374:                  */
375:                 private Set<IType> getTypeForSpecificType(ValidationServices services,
376:                                 IReadOnlyQueryEnvironment queryEnvironment, List<IType> argTypes, final EClass receiverEClass) {
377:                         final Set<IType> result = new LinkedHashSet<IType>();
378:
379:                         if (argTypes.size() == 1) {
380:                                 for (EClass containingEClass : queryEnvironment.getEPackageProvider().getContainingEClasses(
381:                                                 receiverEClass)) {
382:                                         result.add(new EClassifierType(queryEnvironment, containingEClass));
383:                                 }
384:                                 if (result.isEmpty()) {
385:                                         result.add(services.nothing("%s can't be contained", argTypes.get(0)));
386:                                 }
387:                         } else if (argTypes.size() == 2) {
388:                                 final IType filterType = argTypes.get(1);
389:                                 for (EClass containingEClass : queryEnvironment.getEPackageProvider()
390:                                                 .getAllContainingEClasses(receiverEClass)) {
391:                                         final IType lowerType = services.lower(new EClassifierType(queryEnvironment,
392:                                                         containingEClass), filterType);
393:                                         if (lowerType != null) {
394:                                                 result.add(lowerType);
395:                                         }
396:                                 }
397:                                 if (result.isEmpty()) {
398:                                         result.add(services.nothing(S_CAN_T_CONTAIN_DIRECTLY_OR_INDIRECTLY_S, filterType,
399:                                                         argTypes.get(0)));
400:                                 }
401:                         }
402:
403:                         return result;
404:                 }
405:
406:         }
407:
408:         /**
409:          * EContainerOrSelf {@link IService}.
410:          *
411:          * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a>
412:          */
413:         private static final class EContainerOrSelfService extends FilterService {
414:
415:                 /**
416:                  * Creates a new service instance given a method and an instance.
417:                  *
418:                  * @param serviceMethod
419:                  * the method that realizes the service
420:                  * @param serviceInstance
421:                  * the instance on which the service must be called
422:                  */
423:                 private EContainerOrSelfService(Method serviceMethod, Object serviceInstance) {
424:                         super(serviceMethod, serviceInstance);
425:                 }
426:
427:                 /**
428:                  * {@inheritDoc}
429:                  *
430:                  * @see org.eclipse.acceleo.query.runtime.impl.JavaMethodService#getType(org.eclipse.acceleo.query.ast.Call,
431:                  * org.eclipse.acceleo.query.runtime.impl.ValidationServices,
432:                  * org.eclipse.acceleo.query.runtime.IValidationResult,
433:                  * org.eclipse.acceleo.query.runtime.IReadOnlyQueryEnvironment, java.util.List)
434:                  */
435:                 @Override
436:                 public Set<IType> getType(Call call, ValidationServices services, IValidationResult validationResult,
437:                                 IReadOnlyQueryEnvironment queryEnvironment, List<IType> argTypes) {
438:                         final Set<IType> result = new LinkedHashSet<IType>();
439:
440:                         if (argTypes.get(0).getType() instanceof EClass) {
441:                                 final EClass eCls = (EClass)argTypes.get(0).getType();
442:                                 if (eCls == EcorePackage.eINSTANCE.getEObject()) {
443:                                         result.add(new EClassifierType(queryEnvironment,
444:                                                         ((EClassifierLiteralType)argTypes.get(1)).getType()));
445:                                 } else {
446:                                         result.addAll(getTypeForSpecificType(services, queryEnvironment, argTypes, eCls));
447:                                 }
448:                         } else {
449:                                 result.add(services.nothing(ONLY_E_CLASS_CAN_BE_CONTAINED_INTO_OTHER_E_CLASSES_NOT_S,
450:                                                 argTypes.get(0)));
451:                         }
452:
453:                         return result;
454:                 }
455:
456:                 /**
457:                  * Gets the {@link IType} of elements returned by the service when the receiver type is not the
458:                  * {@link EObject} {@link EClass}.
459:                  *
460:                  * @param services
461:                  * the {@link ValidationServices}
462:                  * @param queryEnvironment
463:                  * the {@link IReadOnlyQueryEnvironment}
464:                  * @param argTypes
465:                  * arguments {@link IType}
466:                  * @param receiverEClass
467:                  * the receiver type can't be {@link EObject} {@link EClass}
468:                  * @return the {@link IType} of elements returned by the service when the receiver type is not the
469:                  * {@link EObject} {@link EClass}
470:                  */
471:                 private Set<IType> getTypeForSpecificType(ValidationServices services,
472:                                 IReadOnlyQueryEnvironment queryEnvironment, List<IType> argTypes, final EClass receiverEClass) {
473:                         final Set<IType> result = new LinkedHashSet<IType>();
474:
475:                         final IType lowerSelfType = services.lower(argTypes.get(0), argTypes.get(1));
476:                         if (lowerSelfType != null) {
477:                                 result.add(lowerSelfType);
478:                         }
479:                         final IType filterType = argTypes.get(1);
480:                         for (EClass containingEClass : queryEnvironment.getEPackageProvider().getAllContainingEClasses(
481:                                         receiverEClass)) {
482:                                 final IType lowerType = services.lower(
483:                                                 new EClassifierType(queryEnvironment, containingEClass), filterType);
484:                                 if (lowerType != null) {
485:                                         result.add(lowerType);
486:                                 }
487:                         }
488:                         if (result.isEmpty()) {
489:                                 result.add(services.nothing(S_CAN_T_CONTAIN_DIRECTLY_OR_INDIRECTLY_S, filterType, argTypes
490:                                                 .get(0)));
491:                         }
492:
493:                         return result;
494:                 }
495:
496:         }
497:
498:         /**
499:          * EContents {@link IService}.
500:          *
501:          * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a>
502:          */
503:         private static final class EContentsService extends FilterService {
504:
505:                 /**
506:                  * Creates a new service instance given a method and an instance.
507:                  *
508:                  * @param serviceMethod
509:                  * the method that realizes the service
510:                  * @param serviceInstance
511:                  * the instance on which the service must be called
512:                  */
513:                 private EContentsService(Method serviceMethod, Object serviceInstance) {
514:                         super(serviceMethod, serviceInstance);
515:                 }
516:
517:                 @Override
518:                 public Set<IType> getType(Call call, ValidationServices services, IValidationResult validationResult,
519:                                 IReadOnlyQueryEnvironment queryEnvironment, List<IType> argTypes) {
520:                         final Set<IType> result = new LinkedHashSet<IType>();
521:
522:                         if (argTypes.get(0).getType() instanceof EClass) {
523:                                 final EClass eCls = (EClass)argTypes.get(0).getType();
524:                                 if (eCls == EcorePackage.eINSTANCE.getEObject()) {
525:                                         if (argTypes.size() == 1) {
526:                                                 result.add(new SequenceType(queryEnvironment, argTypes.get(0)));
527:                                         } else if (argTypes.size() == 2 && argTypes.get(1) instanceof EClassifierLiteralType) {
528:                                                 result.add(new SequenceType(queryEnvironment, new EClassifierType(queryEnvironment,
529:                                                                 ((EClassifierLiteralType)argTypes.get(1)).getType())));
530:                                         } else if (argTypes.size() == 2 && argTypes.get(1) instanceof EClassifierSetLiteralType) {
531:                                                 for (EClassifier eClsFilter : ((EClassifierSetLiteralType)argTypes.get(1))
532:                                                                 .getEClassifiers()) {
533:                                                         result.add(new SequenceType(queryEnvironment, new EClassifierType(
534:                                                                         queryEnvironment, eClsFilter)));
535:                                                 }
536:                                         } else if (argTypes.size() == 2) {
537:                                                 result.addAll(super.getType(call, services, validationResult, queryEnvironment,
538:                                                                 argTypes));
539:                                         }
540:                                 } else {
541:                                         result.addAll(getTypeForSpecificType(services, queryEnvironment, argTypes, eCls));
542:                                 }
543:                         } else {
544:                                 result.add(new SequenceType(queryEnvironment, services.nothing(
545:                                                 "Only EClass can contain other EClasses not %s", argTypes.get(0))));
546:                         }
547:
548:                         return result;
549:                 }
550:
551:                 /**
552:                  * Gets the {@link IType} of elements returned by the service when the receiver type is not the
553:                  * {@link EObject} {@link EClass}.
554:                  *
555:                  * @param services
556:                  * the {@link ValidationServices}
557:                  * @param queryEnvironment
558:                  * the {@link IReadOnlyQueryEnvironment}
559:                  * @param argTypes
560:                  * arguments {@link IType}
561:                  * @param receiverEClass
562:                  * the receiver type can't be {@link EObject} {@link EClass}
563:                  * @return the {@link IType} of elements returned by the service when the receiver type is not the
564:                  * {@link EObject} {@link EClass}
565:                  */
566:                 private Set<IType> getTypeForSpecificType(ValidationServices services,
567:                                 IReadOnlyQueryEnvironment queryEnvironment, List<IType> argTypes, final EClass receiverEClass) {
568:                         final Set<IType> result = new LinkedHashSet<IType>();
569:
570:                         if (argTypes.size() == 1) {
571:                                 final Set<IType> containedTypes = new LinkedHashSet<IType>();
572:                                 for (EClass contained : queryEnvironment.getEPackageProvider().getContainedEClasses(
573:                                                 receiverEClass)) {
574:                                         containedTypes.add(new SequenceType(queryEnvironment, new EClassifierType(
575:                                                         queryEnvironment, contained)));
576:                                 }
577:                                 result.addAll(containedTypes);
578:                                 if (result.isEmpty()) {
579:                                         result.add(new SequenceType(queryEnvironment, services.nothing(
580:                                                         "%s doesn't contain any other EClass", argTypes.get(0))));
581:                                 }
582:                         } else if (argTypes.size() == 2) {
583:                                 final Set<IType> filterTypes = Sets.newLinkedHashSet();
584:                                 if (argTypes.get(1) instanceof EClassifierSetLiteralType) {
585:                                         for (EClassifier eClassifier : ((EClassifierSetLiteralType)argTypes.get(1))
586:                                                         .getEClassifiers()) {
587:                                                 filterTypes.add(new EClassifierType(queryEnvironment, eClassifier));
588:                                         }
589:                                 } else if (argTypes.get(1) instanceof EClassifierLiteralType) {
590:                                         filterTypes.add(argTypes.get(1));
591:                                 } else {
592:                                         final Collection<EClassifier> eObjectEClasses = queryEnvironment.getEPackageProvider()
593:                                                         .getTypes("ecore", "EObject");
594:                                         for (EClassifier eObjectEClass : eObjectEClasses) {
595:                                                 filterTypes.add(new EClassifierType(queryEnvironment, eObjectEClass));
596:                                         }
597:                                 }
598:                                 for (IType filterType : filterTypes) {
599:                                         for (EClass containedEClass : queryEnvironment.getEPackageProvider()
600:                                                         .getContainedEClasses(receiverEClass)) {
601:                                                 final IType lowerType = services.lower(new EClassifierType(queryEnvironment,
602:                                                                 containedEClass), filterType);
603:                                                 if (lowerType != null) {
604:                                                         result.add(new SequenceType(queryEnvironment, lowerType));
605:                                                 }
606:                                         }
607:                                 }
608:                                 if (result.isEmpty()) {
609:                                         result.add(new SequenceType(queryEnvironment, services.nothing(
610:                                                         "%s can't contain %s direclty", argTypes.get(0), argTypes.get(1))));
611:                                 }
612:                         }
613:
614:                         return result;
615:                 }
616:
617:         }
618:
619:         /**
620:          * AllInstances {@link IService}.
621:          *
622:          * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a>
623:          */
624:         private final class AllInstancesService extends EAllContentsService {
625:
626:                 /**
627:                  * Creates a new service instance given a method and an instance.
628:                  *
629:                  * @param serviceMethod
630:                  * the method that realizes the service
631:                  * @param serviceInstance
632:                  * the instance on which the service must be called
633:                  */
634:                 private AllInstancesService(Method serviceMethod, Object serviceInstance) {
635:                         super(serviceMethod, serviceInstance);
636:                 }
637:
638:                 /**
639:                  * {@inheritDoc}
640:                  *
641:                  * @see org.eclipse.acceleo.query.services.EAllContentsService#getType(org.eclipse.acceleo.query.ast.Call,
642:                  * org.eclipse.acceleo.query.runtime.impl.ValidationServices,
643:                  * org.eclipse.acceleo.query.runtime.IValidationResult,
644:                  * org.eclipse.acceleo.query.runtime.IReadOnlyQueryEnvironment, java.util.List)
645:                  */
646:                 @Override
647:                 public Set<IType> getType(Call call, ValidationServices services, IValidationResult validationResult,
648:                                 IReadOnlyQueryEnvironment queryEnv, List<IType> argTypes) {
649:                         final Set<IType> result;
650:
651:                         if (rootProvider == null) {
652:                                 result = Sets.newLinkedHashSet();
653:                                 result.add(new SequenceType(queryEnv, services.nothing("No IRootEObjectProvider registered")));
654:                         } else {
655:                                 List<IType> newArgTypes = Lists.newArrayList(argTypes);
656:                                 final Collection<EClassifier> eObjectEClasses = queryEnv.getEPackageProvider().getTypes(
657:                                                 "ecore", "EObject");
658:                                 for (EClassifier eObjectEClass : eObjectEClasses) {
659:                                         newArgTypes.add(0, new EClassifierType(queryEnv, eObjectEClass));
660:                                 }
661:
662:                                 result = super.getType(call, services, validationResult, queryEnv, newArgTypes);
663:                         }
664:
665:                         return result;
666:                 }
667:         }
668:
669:         /**
670:          * EInverse {@link IService}.
671:          *
672:          * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a>
673:          */
674:         private static final class EInverseService extends FilterService {
675:
676:                 /**
677:                  * Creates a new service instance given a method and an instance.
678:                  *
679:                  * @param serviceMethod
680:                  * the method that realizes the service
681:                  * @param serviceInstance
682:                  * the instance on which the service must be called
683:                  */
684:                 private EInverseService(Method serviceMethod, Object serviceInstance) {
685:                         super(serviceMethod, serviceInstance);
686:                 }
687:
688:                 /**
689:                  * Creates a new service instance given a method and an instance.
690:                  *
691:                  * @param serviceMethod
692:                  * the method that realizes the service
693:                  * @param serviceInstance
694:                  * the instance on which the service must be called
695:                  * @param filterIndex
696:                  * the index of the filtering {@link IType}
697:                  * @since 4.0.0
698:                  */
699:                 private EInverseService(Method serviceMethod, Object serviceInstance, int filterIndex) {
700:                         super(serviceMethod, serviceInstance, filterIndex);
701:                 }
702:
703:                 @Override
704:                 public Set<IType> getType(Call call, ValidationServices services, IValidationResult validationResult,
705:                                 IReadOnlyQueryEnvironment queryEnvironment, List<IType> argTypes) {
706:                         final Set<IType> result = new LinkedHashSet<IType>();
707:
708:                         if (argTypes.get(0).getType() instanceof EClass) {
709:                                 final EClass eCls = (EClass)argTypes.get(0).getType();
710:                                 if (eCls == EcorePackage.eINSTANCE.getEObject()) {
711:                                         if (argTypes.size() == 1 || !(argTypes.get(1).getType() instanceof EClass)) {
712:                                                 result.add(new SetType(queryEnvironment, argTypes.get(0)));
713:                                         } else if (argTypes.size() == 2) {
714:                                                 result.add(new SetType(queryEnvironment, new EClassifierType(queryEnvironment,
715:                                                                 ((EClassifierLiteralType)argTypes.get(1)).getType())));
716:                                         }
717:                                 } else {
718:                                         result.addAll(getTypeForSpecificType(call, services, queryEnvironment, argTypes, eCls));
719:                                 }
720:                         } else {
721:                                 result.add(new SetType(queryEnvironment, services.nothing(
722:                                                 "Only EClass can have inverse not %s", argTypes.get(0))));
723:                         }
724:
725:                         return result;
726:                 }
727:
728:                 /**
729:                  * Gets the {@link IType} of elements returned by the service when the receiver type is not the
730:                  * {@link EObject} {@link EClass}.
731:                  *
732:                  * @param call
733:                  * the {@link Call}
734:                  * @param services
735:                  * the {@link ValidationServices}
736:                  * @param queryEnvironment
737:                  * the {@link IReadOnlyQueryEnvironment}
738:                  * @param argTypes
739:                  * arguments {@link IType}
740:                  * @param receiverEClass
741:                  * the receiver type can't be {@link EObject} {@link EClass}
742:                  * @return the {@link IType} of elements returned by the service when the receiver type is not the
743:                  * {@link EObject} {@link EClass}
744:                  */
745:                 private Set<IType> getTypeForSpecificType(Call call, ValidationServices services,
746:                                 IReadOnlyQueryEnvironment queryEnvironment, List<IType> argTypes, final EClass receiverEClass) {
747:                         final Set<IType> result = new LinkedHashSet<IType>();
748:
749:                         final Set<EClass> inverseEClasses = queryEnvironment.getEPackageProvider().getInverseEClasses(
750:                                         receiverEClass);
751:                         if (argTypes.size() == 1 || !(argTypes.get(1).getType() instanceof EClass)) {
752:                                 result.addAll(getTypeForSpecificTypeNoFilterOrName(call, services, queryEnvironment,
753:                                                 argTypes, inverseEClasses));
754:                         } else if (argTypes.size() == 2) {
755:                                 result.addAll(getTypeForSpecificTypeFilter(services, queryEnvironment, argTypes,
756:                                                 inverseEClasses));
757:                         }
758:
759:                         return result;
760:                 }
761:
762:                 /**
763:                  * Computes {@link IType} for {@link EObjectServices#eInverse(EObject) eInverse(EObject)} and
764:                  * {@link EObjectServices#eInverse(EObject, String) eInverse(EObject, String)}.
765:                  *
766:                  * @param call
767:                  * the {@link Call}
768:                  * @param services
769:                  * the {@link ValidationServices}
770:                  * @param queryEnvironment
771:                  * the {@link IReadOnlyQueryEnvironment}
772:                  * @param argTypes
773:                  * arguments {@link IType}
774:                  * @param inverseEClasses
775:                  * the {@link Set} of inverse {@link EClass}
776:                  * @return the {@link Set} of possible {@link IType}
777:                  */
778:                 private Set<IType> getTypeForSpecificTypeNoFilterOrName(Call call, ValidationServices services,
779:                                 IReadOnlyQueryEnvironment queryEnvironment, List<IType> argTypes,
780:                                 final Set<EClass> inverseEClasses) {
781:                         final Set<IType> result = new LinkedHashSet<IType>();
782:
783:                         final String featureName;
784:                         if (call.getArguments().size() == 2 && call.getArguments().get(1) instanceof StringLiteral) {
785:                                 featureName = ((StringLiteral)call.getArguments().get(1)).getValue();
786:                         } else {
787:                                 featureName = null;
788:                         }
789:                         for (EClass inverseEClass : inverseEClasses) {
790:                                 if (featureName == null || inverseEClass.getEStructuralFeature(featureName) != null) {
791:                                         result.add(new SetType(queryEnvironment, new EClassifierType(queryEnvironment,
792:                                                         inverseEClass)));
793:                                 }
794:                         }
795:                         if (result.isEmpty()) {
796:                                 result.add(new SetType(queryEnvironment, services.nothing("%s don't have inverse", argTypes
797:                                                 .get(0))));
798:                         }
799:
800:                         return result;
801:                 }
802:
803:                 /**
804:                  * Computes {@link IType} for {@link EObjectServices#eInverse(EObject, EClassifier) eInverse(EObject,
805:                  * EClassifier)}.
806:                  *
807:                  * @param services
808:                  * the {@link ValidationServices}
809:                  * @param queryEnvironment
810:                  * the {@link IReadOnlyQueryEnvironment}
811:                  * @param argTypes
812:                  * arguments {@link IType}
813:                  * @param inverseEClasses
814:                  * the {@link Set} of inverse {@link EClass}
815:                  * @return the {@link Set} of possible {@link IType}
816:                  */
817:                 private Set<IType> getTypeForSpecificTypeFilter(ValidationServices services,
818:                                 IReadOnlyQueryEnvironment queryEnvironment, List<IType> argTypes,
819:                                 final Set<EClass> inverseEClasses) {
820:                         final Set<IType> result = new LinkedHashSet<IType>();
821:
822:                         final IType filterType = argTypes.get(1);
823:                         for (EClass inverseEClass : inverseEClasses) {
824:                                 final IType lowerType = services.lower(new EClassifierType(queryEnvironment, inverseEClass),
825:                                                 filterType);
826:                                 if (lowerType != null) {
827:                                         result.add(new SetType(queryEnvironment, lowerType));
828:                                 }
829:                         }
830:                         if (result.isEmpty()) {
831:                                 result.add(new SetType(queryEnvironment, services.nothing("%s don't have inverse to %s",
832:                                                 argTypes.get(0), filterType)));
833:                         }
834:
835:                         return result;
836:                 }
837:         }
838:
839:         /**
840:          * EGet {@link IService}.
841:          *
842:          * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a>
843:          */
844:         private static final class EGetService extends JavaMethodService {
845:
846:                 /**
847:                  * Creates a new service instance given a method and an instance.
848:                  *
849:                  * @param method
850:                  * the method that realizes the service
851:                  * @param serviceInstance
852:                  * the instance on which the service must be called
853:                  */
854:                 public EGetService(Method method, Object serviceInstance) {
855:                         super(method, serviceInstance);
856:                 }
857:
858:                 /**
859:                  * {@inheritDoc}
860:                  *
861:                  * @see org.eclipse.acceleo.query.runtime.impl.JavaMethodService#getType(org.eclipse.acceleo.query.ast.Call,
862:                  * org.eclipse.acceleo.query.runtime.impl.ValidationServices,
863:                  * org.eclipse.acceleo.query.runtime.IValidationResult,
864:                  * org.eclipse.acceleo.query.runtime.IReadOnlyQueryEnvironment, java.util.List)
865:                  */
866:                 @Override
867:                 public Set<IType> getType(Call call, ValidationServices services, IValidationResult validationResult,
868:                                 IReadOnlyQueryEnvironment queryEnvironment, List<IType> argTypes) {
869:                         final Set<IType> result = new LinkedHashSet<IType>();
870:
871:                         if (call.getArguments().get(1) instanceof StringLiteral) {
872:                                 final String featureName = ((StringLiteral)call.getArguments().get(1)).getValue();
873:                                 final EClass eCls = (EClass)argTypes.get(0).getType();
874:                                 final EStructuralFeature feature = eCls.getEStructuralFeature(featureName);
875:                                 if (feature != null) {
876:                                         if (feature.isMany()) {
877:                                                 result.add(new SetType(queryEnvironment, new EClassifierType(queryEnvironment,
878:                                                                 feature.getEType())));
879:                                         } else {
880:                                                 result.add(new EClassifierType(queryEnvironment, feature.getEType()));
881:                                         }
882:                                 } else {
883:                                         result.add(services.nothing("EStructuralFeature %s not found for %s", featureName,
884:                                                         argTypes.get(0)));
885:                                 }
886:                         } else {
887:                                 result.add(new ClassType(queryEnvironment, Object.class));
888:                         }
889:
890:                         return result;
891:                 }
892:         }
893:
894:         /**
895:          * The cross referencer needed to realize the service eInverse().
896:          */
897:         private final CrossReferenceProvider crossReferencer;
898:
899:         /**
900:          * The root provider needed to realize the service allInstances().
901:          */
902:         private final IRootEObjectProvider rootProvider;
903:
904:         /**
905:          * The {@link IReadOnlyQueryEnvironment}.
906:          */
907:         private final IReadOnlyQueryEnvironment queryEnvironment;
908:
909:         /**
910:          * Constructor.
911:          *
912:          * @param queryEnvironment
913:          * the {@link IReadOnlyQueryEnvironment}
914:          * @param crossReferencer
915:          * the cross referencer needed to realize the service eInverse()
916:          * @param rootProvider
917:          * the root provider needed to realize the service allInstances()
918:          */
919:         public EObjectServices(IReadOnlyQueryEnvironment queryEnvironment,
920:                         CrossReferenceProvider crossReferencer, IRootEObjectProvider rootProvider) {
921:                 this.queryEnvironment = queryEnvironment;
922:                 this.crossReferencer = crossReferencer;
923:                 this.rootProvider = rootProvider;
924:         }
925:
926:         /**
927:          * {@inheritDoc}
928:          *
929:          * @see org.eclipse.acceleo.query.runtime.impl.AbstractServiceProvider#getService(java.lang.reflect.Method)
930:          */
931:         @Override
932:         protected IService getService(Method publicMethod) {
933:                 final IService result;
934:
935:                 if ("eContents".equals(publicMethod.getName())) {
936:                         result = new EContentsService(publicMethod, this);
937:                 } else if ("eAllContents".equals(publicMethod.getName())) {
938:                         result = new EAllContentsService(publicMethod, this);
939:                 } else if ("eContainer".equals(publicMethod.getName())) {
940:                         result = new EContainerService(publicMethod, this);
941:                 } else if ("eContainerOrSelf".equals(publicMethod.getName())) {
942:                         result = new EContainerOrSelfService(publicMethod, this);
943:                 } else if ("eInverse".equals(publicMethod.getName())) {
944:                         if (publicMethod.getParameterTypes().length == 2
945:                                         && publicMethod.getParameterTypes()[1] == String.class) {
946:                                 // no filter for eInverse(EObject, String)
947:                                 result = new EInverseService(publicMethod, this, 10);
948:                         } else {
949:                                 result = new EInverseService(publicMethod, this);
950:                         }
951:                 } else if ("allInstances".equals(publicMethod.getName())) {
952:                         result = new AllInstancesService(publicMethod, this);
953:                 } else if (AstBuilderListener.FEATURE_ACCESS_SERVICE_NAME.equals(publicMethod.getName())) {
954:                         result = new EObjectFeatureAccess(publicMethod, this);
955:                 } else if ("eGet".equals(publicMethod.getName())) {
956:                         result = new EGetService(publicMethod, this);
957:                 } else {
958:                         result = new JavaMethodService(publicMethod, this);
959:                 }
960:
961:                 return result;
962:         }
963:
964:         // @formatter:off
965:         @Documentation(
966:                 value = "Returns a sequence of the EObjects recursively contained in the specified root eObject.",
967:                 params = {
968:                         @Param(name = "eObject", value = "The root of the content tree")
969:                 },
970:                 result = "The recursive content of the specified eObject.",
971:                 examples = {
972:                         @Example(
973:                                 expression = "anEPackage.eAllContents()",
974:                                 result = "Sequence{firstEClass, firstEAttribute, secondEClass, firstDataType}"
975:                         )
976:                 }
977:         )
978:         // @formatter:on
979:         public List<EObject> eAllContents(EObject eObject) {
980:                 return Lists.newArrayList(eObject.eAllContents());
981:         }
982:
983:         // @formatter:off
984:         @Documentation(
985:                 value = "Returns a sequence of the EObjects recursively contained in the specified root eObject and that are " +
986:                                 "instances of the specified EClass",
987:                 params = {
988:                         @Param(name = "eObject", value = "The root of the content tree"),
989:                         @Param(name = "type", value = "The type used to select elements")
990:                 },
991:                 result = "The recursive content of the specified eObject.",
992:                 examples = {
993:                         @Example(
994:                                 expression = "anEPackage.eAllContents(ecore::EClass)",
995:                                 result = "Sequence{firstEClass, secondEClass}"
996:                         )
997:                 }
998:         )
999:         // @formatter:on
1000:         public List<EObject> eAllContents(EObject eObject, final EClass type) {
1001:                 if (type == EcorePackage.eINSTANCE.getEObject()) {
1002:                         return eAllContents(eObject);
1003:                 }
1004:                 final Set<EClass> types = Sets.newLinkedHashSet();
1005:                 types.add(type);
1006:
1007:                 return eAllContents(eObject, types);
1008:         }
1009:
1010:         // @formatter:off
1011:         @Documentation(
1012:                 value = "Returns a sequence of the EObjects recursively contained in the specified root eObject and that are " +
1013:                                 "instances of the specified EClass",
1014:                 params = {
1015:                         @Param(name = "eObject", value = "The root of the content tree"),
1016:                         @Param(name = "types", value = "The set of types used to select elements")
1017:                 },
1018:                 result = "The recursive content of the specified eObject.",
1019:                 examples = {
1020:                         @Example(
1021:                                 expression = "anEPackage.eAllContents({ecore::EPackage | ecore::EClass})",
1022:                                 result = "Sequence{ePackage, eClass, ...}"
1023:                         )
1024:                 }
1025:         )
1026:         // @formatter:on
1027:         public List<EObject> eAllContents(EObject eObject, final Set<EClass> types) {
1028:                 final List<EObject> result;
1029:
1030:                 if (types != null) {
1031:                         final Set<EStructuralFeature> features = Sets.newLinkedHashSet();
1032:                         for (EClass type : types) {
1033:                                 features.addAll(queryEnvironment.getEPackageProvider().getAllContainingEStructuralFeatures(
1034:                                                 type));
1035:                         }
1036:                         result = eAllContents(eObject, types, features);
1037:                 } else {
1038:                         result = Collections.emptyList();
1039:                 }
1040:
1041:                 return result;
1042:         }
1043:
1044:         /**
1045:          * Returns a list of the {@link EObject} recursively contained in the specified root eObject and that are
1046:          * instances of the specified {@link EClass} or one of its {@link EClass#getEAllSuperTypes() super types}.
1047:          *
1048:          * @param eObject
1049:          * the root {@link EObject} to visit.
1050:          * @param types
1051:          * the filtering {@link Set} of {@link EClass}
1052:          * @param features
1053:          * the set of {@link EStructuralFeature} to navigate
1054:          * @return the recursive filtered content of the given {@link EObject}
1055:          */
1056:         private List<EObject> eAllContents(EObject eObject, Set<EClass> types,
1057:                         final Set<EStructuralFeature> features) {
1058:                 List<EObject> allChildrens = Lists.newArrayList();
1059:                 if (eObject == null) {
1060:                         throw new NullPointerException();
1061:                 }
1062:                 if (!features.isEmpty()) {
1063:
1064:                         final AbstractTreeIterator<EObject> treeIterator = new FilteredContentIterator(eObject, false,
1065:                                         features);
1066:                         while (treeIterator.hasNext()) {
1067:                                 EObject child = treeIterator.next();
1068:                                 if (eIsInstanceOf(child, types)) {
1069:                                         allChildrens.add(child);
1070:                                 }
1071:                         }
1072:
1073:                 }
1074:
1075:                 return allChildrens;
1076:
1077:         }
1078:
1079:         /**
1080:          * Tells if the given {@link EObject} is an instance of one of the given {@link EClass}.
1081:          *
1082:          * @param value
1083:          * the {@link EObject} to check
1084:          * @param types
1085:          * the {@link Set} of {@link EClass}
1086:          * @return <code>true</code> if the given {@link EObject} is an instance of one of the given
1087:          * {@link EClass}, <code>false</code> otherwise
1088:          */
1089:         private boolean eIsInstanceOf(EObject value, Set<EClass> types) {
1090:                 for (EClass type : types) {
1091:                         if (type.isSuperTypeOf(((EObject)value).eClass()) || type.isInstance(value)) {
1092:                                 return true;
1093:                         }
1094:                 }
1095:                 return false;
1096:         }
1097:
1098:         // @formatter:off
1099:         @Documentation(
1100:                 value = "Returns the contents of the specified EObject instance.",
1101:                 params = {
1102:                         @Param(name = "eObject", value = "The eObject which content is requested.")
1103:                 },
1104:                 result = "The content of the specified eObject.",
1105:                 examples = {
1106:                         @Example(
1107:                                 expression = "anEPackage.eContents()",
1108:                                 result = "Sequence{firstEClass, secondEClass, firstDataType}"
1109:                         )
1110:                 }
1111:         )
1112:         // @formatter:on
1113:         public List<EObject> eContents(EObject eObject) {
1114:                 return Lists.newArrayList(eObject.eContents());
1115:         }
1116:
1117:         // @formatter:off
1118:         @Documentation(
1119:                 value = "Returns a sequence made of the instances of the specified type in the contents of the specified eObject.",
1120:                 params = {
1121:                         @Param(name = "eObject", value = "The eObject which content is requested."),
1122:                         @Param(name = "type", value = "The type filter.")
1123:                 },
1124:                 result = "The filtered content of the specified eObject.",
1125:                 examples = {
1126:                         @Example(
1127:                                 expression = "anEPackage.eContents(ecore::EDataType)",
1128:                                 result = "Sequence{firstDataType}"
1129:                         )
1130:                 }
1131:         )
1132:         // @formatter:on
1133:         public List<EObject> eContents(EObject eObject, final EClass type) {
1134:                 if (type == EcorePackage.eINSTANCE.getEObject()) {
1135:                         return eContents(eObject);
1136:                 }
1137:                 final Set<EClass> eClasses = new LinkedHashSet<EClass>();
1138:                 eClasses.add(type);
1139:
1140:                 return eContents(eObject, eClasses);
1141:         }
1142:
1143:         // @formatter:off
1144:         @Documentation(
1145:                 value = "Returns a sequence made of the instances of the specified types in the contents of the specified eObject.",
1146:                 params = {
1147:                         @Param(name = "eObject", value = "The eObject which content is requested."),
1148:                         @Param(name = "types", value = "The Set of types filter.")
1149:                 },
1150:                 result = "The filtered content of the specified eObject.",
1151:                 examples = {
1152:                         @Example(
1153:                                 expression = "anEPackage.eContents({ecore::EPackage | ecore::EClass})",
1154:                                 result = "Sequence{SubEPackage, eClass, ... }"
1155:                         )
1156:                 }
1157:         )
1158:         // @formatter:on
1159:         public List<EObject> eContents(EObject eObject, final Set<EClass> types) {
1160:                 final List<EObject> result;
1161:
1162:                 if (types != null) {
1163:                         final Set<EStructuralFeature> features = Sets.newLinkedHashSet();
1164:                         for (EClass type : types) {
1165:                                 features.addAll(queryEnvironment.getEPackageProvider().getContainingEStructuralFeatures(type));
1166:                         }
1167:                         result = eContents(eObject, types, features);
1168:                 } else {
1169:                         result = Collections.emptyList();
1170:                 }
1171:
1172:                 return result;
1173:         }
1174:
1175:         /**
1176:          * Returns a list of the {@link EObject} directly contained in the specified root eObject and that are
1177:          * instances of the specified {@link EClass} or one of its {@link EClass#getEAllSuperTypes() super types}.
1178:          *
1179:          * @param eObject
1180:          * the root {@link EObject} to visit.
1181:          * @param types
1182:          * the filtering {@link Set} of {@link EClass}
1183:          * @param features
1184:          * the set of {@link EStructuralFeature} to navigate
1185:          * @return the filtered content of the given {@link EObject}
1186:          */
1187:         private List<EObject> eContents(EObject eObject, Set<EClass> types, Set<EStructuralFeature> features) {
1188:                 final List<EObject> result = Lists.newArrayList();
1189:
1190:                 if (!features.isEmpty()) {
1191:                         final EStructuralFeature[] containmentFeatures = ((EClassImpl.FeatureSubsetSupplier)eObject
1192:                                         .eClass().getEAllStructuralFeatures()).containments();
1193:                         for (EStructuralFeature feature : containmentFeatures) {
1194:                                 if (features.contains(feature)) {
1195:                                         final Object child = eObject.eGet(feature);
1196:                                         if (child != null) {
1197:                                                 eContentsVisitChild(result, child, types, feature.isMany(), features);
1198:                                         }
1199:                                 }
1200:                         }
1201:                 }
1202:
1203:                 return result;
1204:         }
1205:
1206:         /**
1207:          * Visits a given child for {@link EObjectServices#eContents(EObject, Set, Set)}.
1208:          *
1209:          * @param result
1210:          * the resulting {@link List} to populate
1211:          * @param child
1212:          * the child to visit
1213:          * @param types
1214:          * the filtering {@link Set} of {@link EClass}
1215:          * @param isMany
1216:          * <code>true</code> if the containing {@link EStructuralFeature}
1217:          * {@link EStructuralFeature#isMany() is many}, <code>false</code> otherwise
1218:          * @param features
1219:          * the set of {@link EStructuralFeature} to navigate
1220:          */
1221:         private void eContentsVisitChild(List<EObject> result, Object child, Set<EClass> types, boolean isMany,
1222:                         Set<EStructuralFeature> features) {
1223:                 if (isMany) {
1224:                         if (child instanceof Collection<?>) {
1225:                                 eContentsVisitCollectionChild(result, (Collection<?>)child, types, features);
1226:                         } else {
1227:                                 throw new IllegalStateException(DON_T_KNOW_WHAT_TO_DO_WITH + child.getClass());
1228:                         }
1229:                 } else if (child instanceof EObject) {
1230:                         if (eIsInstanceOf((EObject)child, types)) {
1231:                                 result.add((EObject)child);
1232:                         }
1233:                 }
1234:         }
1235:
1236:         /**
1237:          * Visits a given {@link Collection} child for {@link EObjectServices#eContents(EObject, Set, Set)}.
1238:          *
1239:          * @param result
1240:          * the resulting {@link List} to populate
1241:          * @param child
1242:          * the child to visit
1243:          * @param types
1244:          * the filtering {@link Set} of {@link EClass}
1245:          * @param features
1246:          * the set of {@link EStructuralFeature} to navigate
1247:          */
1248:         private void eContentsVisitCollectionChild(List<EObject> result, Collection<?> child,
1249:                         final Set<EClass> types, Set<EStructuralFeature> features) {
1250:                 for (Object object : (Collection<?>)child) {
1251:                         if (object instanceof EObject) {
1252:                                 if (eIsInstanceOf((EObject)object, types)) {
1253:                                         result.add((EObject)object);
1254:                                 }
1255:                         }
1256:                 }
1257:         }
1258:
1259:         // @formatter:off
1260:         @Documentation(
1261:                 value = "Returns the container of the specified EObject",
1262:                 params = {
1263:                         @Param(name = "eObject", value = "The eObject which container is requested.")
1264:                 },
1265:                 result = "The container of the specified eObject.",
1266:                 examples = {
1267:                         @Example(
1268:                                 expression = "firstEAttribute.eContainer()",
1269:                                 result = "firstEClass"
1270:                         )
1271:                 }
1272:         )
1273:         // @formatter:on
1274:         public EObject eContainer(EObject eObject) {
1275:                 return eObject.eContainer();
1276:         }
1277:
1278:         // @formatter:off
1279:         @Documentation(
1280:                 value = "Returns the first container of the specified EObject that matches the given type",
1281:                 params = {
1282:                         @Param(name = "eObject", value = "The eObject which container is requested."),
1283:                         @Param(name = "type", value = "The type filter.")
1284:                 },
1285:                 result = "The first container of the specified eObject that matches the given type.",
1286:                 examples = {
1287:                         @Example(
1288:                                 expression = "firstEAttribute.eContainer(ecore::EPackage)",
1289:                                 result = "anEPackage"
1290:                         )
1291:                 }
1292:         )
1293:         // @formatter:on
1294:         public EObject eContainer(EObject eObject, EClass type) {
1295:                 final EObject result;
1296:
1297:                 EObject current = eObject.eContainer();
1298:                 while (current != null && !type.isSuperTypeOf(current.eClass()) && !type.isInstance(current)) {
1299:                         current = current.eContainer();
1300:                 }
1301:                 if (current != null && (type.isSuperTypeOf(current.eClass()) || type.isInstance(current))) {
1302:                         result = current;
1303:                 } else {
1304:                         result = null;
1305:                 }
1306:
1307:                 return result;
1308:         }
1309:
1310:         // @formatter:off
1311:         @Documentation(
1312:                 value = "Returns self or the first container of the specified EObject that matches the given type",
1313:                 params = {
1314:                         @Param(name = "eObject", value = "The eObject which container is requested."),
1315:                         @Param(name = "type", value = "The type filter.")
1316:                 },
1317:                 result = "Self or the first container of the specified eObject that matches the given type.",
1318:                 examples = {
1319:                         @Example(
1320:                                 expression = "firstEAttribute.eContainerOrSelf(ecore::EAttribute)",
1321:                                 result = "firstEAttribute"
1322:                         )
1323:                 }
1324:         )
1325:         // @formatter:on
1326:         public EObject eContainerOrSelf(EObject eObject, EClass type) {
1327:                 final EObject result;
1328:
1329:                 if (type.isSuperTypeOf(eObject.eClass()) || type.isInstance(eObject)) {
1330:                         result = eObject;
1331:                 } else {
1332:                         result = eContainer(eObject, type);
1333:                 }
1334:
1335:                 return result;
1336:         }
1337:
1338:         // @formatter:off
1339:         @Documentation(
1340:                 value = "Returns the EClass of the specified EObject",
1341:                 params = {
1342:                         @Param(name = "eObject", value = "The eObject which EClass is requested.")
1343:                 },
1344:                 result = "The EClass of the specified EObject"
1345:         )
1346:         // @formatter:on
1347:         public EClass eClass(EObject eObject) {
1348:                 return eObject.eClass();
1349:         }
1350:
1351:         // @formatter:off
1352:         @Documentation(
1353:                 value = "Returns the containing feature of the specified EObject",
1354:                 params = {
1355:                         @Param(name = "eObject", value = "The eObject which containing feature is requested.")
1356:                 },
1357:                 result = "The containing feature of the specified EObject"
1358:         )
1359:         // @formatter:on
1360:         public EStructuralFeature eContainingFeature(EObject eObject) {
1361:                 return eObject.eContainingFeature();
1362:         }
1363:
1364:         // @formatter:off
1365:         @Documentation(
1366:                 value = "Returns the containment feature of the specified EObject",
1367:                 params = {
1368:                         @Param(name = "eObject", value = "The eObject which containment feature is requested.")
1369:                 },
1370:                 result = "The containment feature of the specified EObject"
1371:         )
1372:         // @formatter:on
1373:         public EReference eContainmentFeature(EObject eObject) {
1374:                 return eObject.eContainmentFeature();
1375:         }
1376:
1377:         // @formatter:off
1378:         @Documentation(
1379:                 value = "Returns the set containing the inverse references.",
1380:                 params = {
1381:                         @Param(name = "eObject", value = "The eObject which inverse references are requested.")
1382:                 },
1383:                 result = "The set of the inverse references"
1384:         )
1385:         // @formatter:on
1386:         public Set<EObject> eInverse(EObject self) {
1387:                 final Set<EObject> result;
1388:
1389:                 final Collection<EStructuralFeature.Setting> settings = crossReferencer.getInverseReferences(self);
1390:                 if (settings == null) {
1391:                         result = Collections.emptySet();
1392:                 } else {
1393:                         result = Sets.newLinkedHashSet();
1394:                         for (EStructuralFeature.Setting setting : settings) {
1395:                                 result.add(setting.getEObject());
1396:                         }
1397:                 }
1398:
1399:                 return result;
1400:         }
1401:
1402:         // @formatter:off
1403:         @Documentation(
1404:                 value = "Returns the elements of the given type from the set of the inverse references of the receiver.",
1405:                 params = {
1406:                         @Param(name = "eObject", value = "The eObject which inverse references are requested."),
1407:                         @Param(name = "type", value = "The type filter."),
1408:                 },
1409:                 result = "The set of the inverse references"
1410:         )
1411:         // @formatter:on
1412:         public Set<EObject> eInverse(EObject self, EClassifier type) {
1413:                 final Set<EObject> result;
1414:
1415:                 final Collection<EStructuralFeature.Setting> settings = crossReferencer.getInverseReferences(self);
1416:                 if (settings == null || type == null) {
1417:                         result = Collections.emptySet();
1418:                 } else {
1419:                         result = Sets.newLinkedHashSet();
1420:                         for (EStructuralFeature.Setting setting : settings) {
1421:                                 if (type.isInstance(setting.getEObject())) {
1422:                                         result.add(setting.getEObject());
1423:                                 }
1424:                         }
1425:                 }
1426:
1427:                 return result;
1428:         }
1429:
1430:         // @formatter:off
1431:         @Documentation(
1432:                 value = "Returns the elements from the set of the inverse references of the receiver that are referencing the receiver " +
1433:                                 "using a feature with the given name.",
1434:                 params = {
1435:                         @Param(name = "eObject", value = "The eObject which inverse references are requested."),
1436:                         @Param(name = "featureName", value = "The feature name."),
1437:                 },
1438:                 result = "The set of the inverse references"
1439:         )
1440:         // @formatter:on
1441:         public Set<EObject> eInverse(EObject self, String featureName) {
1442:                 final Set<EObject> result;
1443:
1444:                 final Collection<EStructuralFeature.Setting> settings = crossReferencer.getInverseReferences(self);
1445:                 if (settings == null) {
1446:                         result = Collections.emptySet();
1447:                 } else {
1448:                         result = Sets.newLinkedHashSet();
1449:                         for (EStructuralFeature.Setting setting : settings) {
1450:                                 if (setting.getEStructuralFeature().getName().equals(featureName)) {
1451:                                         result.add(setting.getEObject());
1452:                                 }
1453:                         }
1454:                 }
1455:
1456:                 return result;
1457:         }
1458:
1459:         // @formatter:off
1460:         @Documentation(
1461:                 value = "Handles calls to the operation \"eGet\". This will fetch the value of the feature named " +
1462:                                 "\"featureName\" on \"source\"",
1463:                 params = {
1464:                         @Param(name = "eObject", value = "The eObject we seek to retrieve a feature value of."),
1465:                         @Param(name = "featureName", value = "The name of the feature which value we need to retrieve."),
1466:                 },
1467:                 result = "The value of the given feature on the given EObject"
1468:         )
1469:         // @formatter:on
1470:         public Object eGet(EObject eObject, final String featureName) {
1471:                 if (eObject == null || featureName == null) {
1472:                         throw new NullPointerException();
1473:                 }
1474:                 final EStructuralFeature feature = eObject.eClass().getEStructuralFeature(featureName);
1475:
1476:                 Object result = null;
1477:                 if (feature != null) {
1478:                         result = eObject.eGet(feature);
1479:                 }
1480:
1481:                 if (result instanceof Set<?>) {
1482:                         result = Sets.newLinkedHashSet((Set<?>)result);
1483:                 } else if (result instanceof EMap<?, ?>) {
1484:                         result = new BasicEMap<Object, Object>(((EMap<?, ?>)result).map());
1485:                 } else if (result instanceof Collection<?>) {
1486:                         result = Lists.newArrayList((Collection<?>)result);
1487:                 }
1488:
1489:                 return result;
1490:         }
1491:
1492:         // @formatter:off
1493:         @Documentation(
1494:                 value = "Returns all instances of the EClass",
1495:                 params = {
1496:                         @Param(name = "type", value = "The EClass"),
1497:                 },
1498:                 result = "all instances of the EClass"
1499:         )
1500:         // @formatter:on
1501:         public List<EObject> allInstances(EClass type) {
1502:                 final List<EObject> result;
1503:
1504:                 if (type != null) {
1505:                         final Set<EClass> types = Sets.newLinkedHashSet();
1506:                         types.add(type);
1507:                         result = allInstances(types);
1508:                 } else {
1509:                         result = Collections.emptyList();
1510:                 }
1511:
1512:                 return result;
1513:         }
1514:
1515:         // @formatter:off
1516:         @Documentation(
1517:                 value = "Returns all instances of any EClass from the OrderedSet",
1518:                 params = {
1519:                         @Param(name = "types", value = "The OrderedSet of EClass"),
1520:                 },
1521:                 result = "all instances of any EClass from the OrderedSet"
1522:         )
1523:         // @formatter:on
1524:         public List<EObject> allInstances(Set<EClass> types) {
1525:                 final List<EObject> result = Lists.newArrayList();
1526:
1527:                 if (rootProvider != null && types != null) {
1528:                         for (EObject root : rootProvider.getRoots()) {
1529:                                 if (eIsInstanceOf(root, types)) {
1530:                                         result.add(root);
1531:                                 }
1532:                                 result.addAll(eAllContents(root, types));
1533:                         }
1534:                 }
1535:
1536:                 return result;
1537:         }
1538:
1539:         // @formatter:off
1540:         @Documentation(
1541:                 value = "Returns the list of all EObjects cross-referenced from the receiver.",
1542:                 params = {
1543:                         @Param(name = "eObject", value = "The eObject of which we need the cross-references."),
1544:                 },
1545:                 result = "The list of all EObjects cross-referenced from the receiver."
1546:         )
1547:         // @formatter:on
1548:         public Object eCrossReferences(EObject eObject) {
1549:                 return Lists.newArrayList(eObject.eCrossReferences());
1550:         }
1551:
1552:         /**
1553:          * Returns the value of the specified feature on the specified object. The object must be an
1554:          * {@link EObject} or a {@link Set}, {@link List} of {@link EObject}.
1555:          *
1556:          * @param context
1557:          * the object in which to read the feature.
1558:          * @param featureName
1559:          * the name of the feature to read.
1560:          * @param diagnostic
1561:          * The status to update in case of warnings or errors during this call.
1562:          * @return the value of the specified feature in the specified object.
1563:          */
1564:         public Object aqlFeatureAccess(EObject self, String featureName) {
1565:                 final Object result;
1566:
1567:                 if (self == null) {
1568:                         final String message = String.format(NON_EOBJECT_FEATURE_ACCESS, featureName, "null");
1569:                         throw new AcceleoQueryEvaluationException(message);
1570:                 } else {
1571:                         EClass eClass = ((EObject)self).eClass();
1572:                         EStructuralFeature feature = eClass.getEStructuralFeature(featureName);
1573:                         if (feature == null) {
1574:                                 final String message = String.format(UNKNOWN_FEATURE, featureName, eClass.getName());
1575:                                 throw new AcceleoQueryEvaluationException(message);
1576:                         } else {
1577:                                 result = ((EObject)self).eGet(feature);
1578:                         }
1579:                 }
1580:
1581:                 return result;
1582:         }
1583:
1584: }