001package org.nasdanika.html.ecore;
002
003import java.nio.charset.StandardCharsets;
004import java.util.Collection;
005import java.util.Collections;
006import java.util.Comparator;
007import java.util.HashSet;
008import java.util.Iterator;
009import java.util.List;
010import java.util.Objects;
011import java.util.Set;
012import java.util.function.BiFunction;
013import java.util.function.Consumer;
014import java.util.function.Predicate;
015import java.util.stream.Collectors;
016
017import org.apache.commons.codec.binary.Hex;
018import org.eclipse.emf.common.notify.Notifier;
019import org.eclipse.emf.common.util.TreeIterator;
020import org.eclipse.emf.common.util.URI;
021import org.eclipse.emf.ecore.EClass;
022import org.eclipse.emf.ecore.EClassifier;
023import org.eclipse.emf.ecore.EGenericType;
024import org.eclipse.emf.ecore.EModelElement;
025import org.eclipse.emf.ecore.ENamedElement;
026import org.eclipse.emf.ecore.EObject;
027import org.eclipse.emf.ecore.EOperation;
028import org.eclipse.emf.ecore.EPackage;
029import org.eclipse.emf.ecore.EReference;
030import org.eclipse.emf.ecore.EStructuralFeature;
031import org.eclipse.emf.ecore.ETypeParameter;
032import org.eclipse.emf.ecore.ETypedElement;
033import org.eclipse.emf.ecore.resource.Resource;
034import org.eclipse.emf.ecore.resource.ResourceSet;
035import org.nasdanika.common.Context;
036import org.nasdanika.common.DiagramGenerator;
037import org.nasdanika.common.MarkdownHelper;
038import org.nasdanika.common.MutableContext;
039import org.nasdanika.common.ProgressMonitor;
040import org.nasdanika.common.PropertyComputer;
041import org.nasdanika.common.Util;
042import org.nasdanika.emf.EmfUtil;
043import org.nasdanika.emf.EmfUtil.EModelElementDocumentation;
044import org.nasdanika.emf.persistence.MarkerFactory;
045import org.nasdanika.exec.content.ContentFactory;
046import org.nasdanika.exec.content.Interpolator;
047import org.nasdanika.exec.content.Markdown;
048import org.nasdanika.exec.content.Text;
049import org.nasdanika.html.model.app.Action;
050import org.nasdanika.html.model.app.AppFactory;
051import org.nasdanika.ncore.util.NcoreUtil; 
052
053public class EModelElementActionSupplier<T extends EModelElement> extends EObjectActionSupplier<T> {
054                
055        protected BiFunction<ENamedElement, String, String> labelProvider;      
056        
057        protected Comparator<ENamedElement> eNamedElementComparator = (a,b) -> labelProvider.apply(a, a.getName()).compareTo(labelProvider.apply(b, b.getName()));
058        
059        public static final String ICONS_BASE = "https://www.nasdanika.org/resources/images/ecore/";
060                
061        /**
062         * Descriptions shorter than this value are put on the top of the tabs, longer
063         * ones end up in their own tab. 
064         */
065        protected int descriptionTabLengthThreshold = 2500;
066
067        protected Context context;
068
069        protected java.util.function.Function<EPackage,String> ePackagePathComputer;
070        protected Predicate<EModelElement> elementPredicate;
071                
072        public EModelElementActionSupplier(
073                        T value, 
074                        Context context, 
075                        java.util.function.Function<EPackage,String> ePackagePathComputer,
076                        Predicate<EModelElement> elementPredicate,
077                        BiFunction<ENamedElement, String, String> labelProvider) {
078                super(value);
079                this.context = context.fork();
080                PropertyComputer eClassifierPropertyComputer = new PropertyComputer() {
081                        
082                        @SuppressWarnings("unchecked")
083                        @Override
084                        public <P> P compute(Context context, String key, String path, Class<P> type) {
085                                Resource contextResource = value.eResource();
086                                EObject contextElement = value;
087                                while (contextElement != null && !(contextElement instanceof EPackage)) {
088                                        contextElement = contextElement.eContainer();
089                                }
090                                
091                                EClassifier targetClassifier = null;
092                                int atIdx = path.indexOf('@');
093                                if (atIdx == -1) {
094                                        if (contextElement == null) {
095                                                return null;
096                                        }
097                                        
098                                        targetClassifier = ((EPackage) contextElement).getEClassifier(path);
099                                } else {
100                                        if (contextResource == null) {
101                                                return null;
102                                        }
103                                        ResourceSet resourceSet = contextResource.getResourceSet();
104                                        if (resourceSet == null) {
105                                                return null;
106                                        }
107                                        TreeIterator<Notifier> cit = resourceSet.getAllContents();
108                                        String targetNsUri = path.substring(atIdx + 1);
109                                        while (cit.hasNext()) {
110                                                Notifier next = cit.next();
111                                                if (next instanceof EPackage) {
112                                                        if (((EPackage) next).getNsURI().equals(targetNsUri)) {
113                                                                targetClassifier = ((EPackage) next).getEClassifier(path.substring(0, atIdx));
114                                                                break;
115                                                        }
116                                                }
117                                        }
118                                }
119                                
120                                if (targetClassifier == null) {
121                                        return null;
122                                }
123
124                                return (P) path(targetClassifier, value instanceof EClassifier ? (EClassifier) value : null);
125                        }
126                        
127                };
128                ((MutableContext) this.context).put("classifier", eClassifierPropertyComputer);
129                this.ePackagePathComputer = ePackagePathComputer;
130                this.elementPredicate = elementPredicate;
131                this.labelProvider = labelProvider;
132        }
133
134        @Override
135        public Action execute(EClass contextClass, ProgressMonitor progressMonitor) {           
136                // TODO - refactor to 
137//              EObject actionPrototype = NcoreUtil.getNasdanikaAnnotationDetail(eObject, "action-prototype");
138//              if (actionPrototype instanceof Action) {
139//                      return EcoreUtil.copy((Action) actionPrototype);
140//              }
141//              if (actionPrototype != null) {
142//                      ActionProvider actionProvider = Objects.requireNonNull((ActionProvider) EcoreUtil.getRegisteredAdapter(actionPrototype, ActionProvider.class), "Cannot adapt " + actionPrototype + " to " + ActionProvider.class);
143//                      return actionProvider.execute(registry, progressMonitor);
144//              }
145//              return AppFactory.eINSTANCE.createAction();
146                
147                
148                Action ret = AppFactory.eINSTANCE.createAction();
149                ret.setIcon(NcoreUtil.getNasdanikaAnnotationDetail(eObject, "icon", ICONS_BASE+eObject.eClass().getName()+".gif"));
150                
151                header(ret, progressMonitor);
152                
153                EModelElementDocumentation documentation = EmfUtil.getDocumentation(eObject); //EObjectAdaptable.getResourceContext(eObject).getString("documentation", EcoreUtil.getDocumentation(eObject));
154//              if (Util.isBlank(markdown)) {
155//                      markdown = EmfUtil.getDocumentation(eObject);
156//              }
157                
158                MarkdownHelper markdownHelper = new MarkdownHelper() {
159                        
160                        @Override
161                        protected URI getResourceBase() {
162                                return documentation.getLocation();
163                        }
164                        
165                        @Override
166                        protected DiagramGenerator getDiagramGenerator() {
167                                return context == null ? super.getDiagramGenerator() : context.get(DiagramGenerator.class, super.getDiagramGenerator()); 
168                        }
169                        
170                };
171                
172                if (documentation != null) {
173                        ret.getContent().add(interpolatedMarkdown(context.interpolateToString(documentation.getDocumentation()), documentation.getLocation(), progressMonitor));                        
174                        String tooltip = NcoreUtil.getNasdanikaAnnotationDetail(eObject, "description", markdownHelper.firstPlainTextSentence(documentation.getDocumentation()));
175                        ret.setTooltip(tooltip);
176                }
177                
178                return ret;
179        }
180        
181        /**
182         * Content before documentation.
183         * @param action
184         * @param progressMonitor
185         */
186        protected void header(Action action, ProgressMonitor progressMonitor) {}
187
188        @Override
189        public double size() {
190                return 1;
191        }
192
193        @Override
194        public String name() {
195                return eObject.eClass().getName();
196        }
197        
198        /**
199         * @param markdown Markdown text
200         * @return Spec for interpolating markdown and then converting to HTML. 
201         */
202        protected Markdown interpolatedMarkdown(String markdown, URI location, ProgressMonitor progressMonitor) {
203                if (Util.isBlank(markdown)) {
204                        return null;
205                }
206                Markdown ret = ContentFactory.eINSTANCE.createMarkdown();
207                Interpolator interpolator = ContentFactory.eINSTANCE.createInterpolator();
208                Text text = ContentFactory.eINSTANCE.createText();
209                text.setContent(markdown);
210                interpolator.setSource(text);
211                ret.setSource(interpolator);
212                ret.setStyle(true);
213                
214                // Creating a marker with EObject resource location for resource resolution in Markdown
215                if (location != null) {
216                        org.nasdanika.ncore.Marker marker = context.get(MarkerFactory.class, MarkerFactory.INSTANCE).createMarker(location.toString(), progressMonitor);
217                        ret.getMarkers().add(marker); 
218                }
219                
220                return ret;
221        }
222        
223        protected String getEModelElementFirstDocSentence(EModelElement modelElement) {
224                EModelElementDocumentation documentation = EmfUtil.getDocumentation(modelElement);
225//              String markdown = EObjectAdaptable.getResourceContext(modelElement).getString("documentation", EcoreUtil.getDocumentation(modelElement));
226//              if (Util.isBlank(markdown)) {
227//                      markdown = EmfUtil.getDocumentation(modelElement);
228//              }
229                if (documentation == null) {
230                        return null;
231                }
232                
233                MarkdownHelper markdownHelper = new MarkdownHelper() {
234                        
235                        @Override
236                        protected URI getResourceBase() {
237                                return documentation.getLocation();
238                        }
239                        
240                        @Override
241                        protected DiagramGenerator getDiagramGenerator() {
242                                return context == null ? super.getDiagramGenerator() : context.get(DiagramGenerator.class, super.getDiagramGenerator()); 
243                        }
244                        
245                };
246                
247                String ret = /* context.computingContext().get(MarkdownHelper.class, markdownHelper) */ markdownHelper.firstPlainTextSentence(documentation.getDocumentation());
248                return String.join(" ", ret.split("\\R")); // Replacing new lines, shall they be in the first sentence, with spaces.            
249        }
250
251        /**
252         * In situations where classes referencing this class are known this method can be overridden. 
253         * @return
254         */     
255        protected Collection<EClass> getReferrers(EClass eClass) {
256                return getReferrers(eClass, true);
257        }
258        
259        /**
260         * In situations where classes referencing this class are known this method can be overridden. 
261         * @return
262         */     
263        private Collection<EClass> getReferrers(EClass eClass, boolean includeAssociations) {
264                TreeIterator<?> acit;
265                Resource eResource = eClass.eResource();
266                if (eResource == null) {
267                        EPackage ePackage = eClass.getEPackage();
268                        if (ePackage == null) {
269                                return Collections.emptySet();
270                        }
271                        acit = ePackage.eAllContents();
272                } else {
273                        ResourceSet resourceSet = eResource.getResourceSet();
274                        acit = resourceSet == null ? eResource.getAllContents() : resourceSet.getAllContents();
275                }
276                Set<EClass> ret = new HashSet<>();
277                acit.forEachRemaining(obj -> {
278                        if (obj instanceof EReference && ((EReference) obj).getEReferenceType() == eClass) {
279                                EClass referrer = ((EReference) obj).getEContainingClass();
280                                if (includeAssociations) {
281                                        for (EClass superReferrer: getReferrers(referrer, false)) {
282                                                for (EReference superReference: superReferrer.getEReferences()) {
283                                                        if (superReference.getEReferenceType() == referrer) {
284                                                                EClass associationTarget = NcoreUtil.getAssociationTarget(superReference);
285                                                                if (associationTarget == eClass) {
286                                                                        ret.add(superReferrer);
287                                                                }
288                                                        }
289                                                }
290                                        }
291                                }
292                                ret.add(referrer);
293                        }
294                });
295                return ret;
296        }
297        
298        /**
299         * Finds all type uses in the resourceset. 
300         * @return
301         */
302        protected Collection<EClass> getUses(EClassifier eClassifier) {
303                TreeIterator<?> acit;
304                Resource eResource = eClassifier.eResource();
305                if (eResource == null) {
306                        EPackage ePackage = eClassifier.getEPackage();
307                        if (ePackage == null) {
308                                return Collections.emptySet();
309                        }
310                        acit = ePackage.eAllContents();
311                } else {
312                        ResourceSet resourceSet = eResource.getResourceSet();
313                        acit = resourceSet == null ? eResource.getAllContents() : resourceSet.getAllContents();
314                }
315                Set<EClass> ret = new HashSet<>();
316                acit.forEachRemaining(obj -> {
317                        if (obj instanceof EClass && (org.nasdanika.emf.EmfUtil.collectTypeDependencies((EClass) obj).contains(eClassifier))) {
318                                ret.add((EClass) obj);
319                        }
320                });
321                return ret;
322        }
323                
324        protected static String cardinality(ETypedElement typedElement) {
325                int lowerBound = typedElement.getLowerBound();
326                int upperBound = typedElement.getUpperBound();
327                String cardinality;
328                if (lowerBound == upperBound) {
329                        cardinality = String.valueOf(lowerBound);
330                } else {
331                        cardinality = lowerBound + ".." + (upperBound == -1 ? "*" : String.valueOf(upperBound));
332                }
333                if (typedElement instanceof EReference && ((EReference) typedElement).isContainment()) {
334                        cardinality = "<B>"+cardinality+"</B>";
335                }
336                return cardinality;
337        }
338        
339        // --- Handling generic types in action text --- 
340
341        protected String computeLabel(EGenericType genericType, ProgressMonitor monitor) {
342                EObject container = genericType.eContainer();
343                EClassifier rawType = genericType.getERawType();
344                String rawTypeText = labelProvider.apply(rawType, rawType.getName()); // rawTypeViewActionSupplierFactory == null ? rawType.getName() : rawTypeViewActionSupplierFactory.create(context).execute(monitor).getText();
345                if (container == null || !container.eIsSet(genericType.eContainingFeature())) {
346                        return rawTypeText;
347                }
348                
349                StringBuilder label = new StringBuilder();
350                if (genericType.getEClassifier() != null) {
351                        label.append(rawTypeText);
352
353                        if (!genericType.getETypeArguments().isEmpty()) {
354                                label.append("&lt;");
355                                for (Iterator<EGenericType> i = genericType.getETypeArguments().iterator(); i.hasNext();) {
356                                        EGenericType typeArgument = i.next();
357                                        label.append(computeLabel(typeArgument, monitor));
358                                        if (i.hasNext()) {
359                                                label.append(", ");
360                                        }
361                                }
362                                label.append("&gt;");
363                        }
364                } else {
365                        ETypeParameter typeParameter = genericType.getETypeParameter();
366                        String name = typeParameter != null ? labelProvider.apply(typeParameter, typeParameter.getName()) : "?";
367                        label.append(name);
368
369                        if (genericType.getELowerBound() != null) {
370                                label.append(" super ");
371                                label.append(computeLabel(genericType.getELowerBound(),  monitor));
372                        } else if (genericType.getEUpperBound() != null) {
373                                label.append(" extends ");
374                                label.append(computeLabel(genericType.getEUpperBound(), monitor));
375                        }
376                }
377                return label.toString();
378        }
379        
380        // --- Generics ---
381        
382        /**
383         * @param eClassifier
384         * @return Type parameters string.
385         */
386        protected String typeParameters(EClassifier eClassifier) {
387                if (eClassifier.getETypeParameters().isEmpty()) {
388                        return "";
389                }
390                StringBuilder typeParameters = new StringBuilder();
391                for (ETypeParameter typeParameter: eClassifier.getETypeParameters()) {
392                        if (typeParameters.length() > 0) {
393                                typeParameters.append(",");
394                        }
395                        typeParameters.append(genericName(typeParameter));
396                }               
397                
398                return "&lt;" + typeParameters +"&gt;";
399        }       
400        
401        protected String genericName(ETypeParameter typeParameter) {
402                StringBuilder ret = new StringBuilder(labelProvider.apply(typeParameter, typeParameter.getName()));
403                for (EGenericType bound : typeParameter.getEBounds()) {
404                        if (bound.getEUpperBound() != null) {
405                                ret.append(" extends ").append(genericName(bound.getEUpperBound()));
406                        }
407                        if (bound.getELowerBound() != null) {
408                                ret.append(" super ").append(genericName(bound.getELowerBound()));
409                        }
410                }
411                
412                return ret.toString();
413        }
414        
415        protected String genericName(EGenericType eGenericType) {
416                StringBuilder ret = new StringBuilder();
417                ETypeParameter eTypeParameter = eGenericType.getETypeParameter();
418                if (eTypeParameter != null) {                   
419                        ret.append(labelProvider.apply(eTypeParameter, eTypeParameter.getName()));
420                } else {
421                        EClassifier eClassifier = eGenericType.getEClassifier();
422                        if (eClassifier != null) {
423                                ret.append(labelProvider.apply(eClassifier, eClassifier.getName()));                    
424                        }
425                }
426                ret.append(genericTypeArguments(eGenericType));
427                return ret.toString();
428        }
429
430        protected String genericTypeArguments(EGenericType eGenericType) {
431                StringBuilder ret = new StringBuilder();
432                Iterator<EGenericType> it = eGenericType.getETypeArguments().iterator();
433                if (it.hasNext()) {
434                        ret.append("<");
435                        while (it.hasNext()) {
436                                ret.append(genericName(it.next()));
437                                if (it.hasNext()) {
438                                        ret.append(",");
439                                }
440                        }
441                        ret.append(">");
442                }
443                return ret.toString();
444        }
445
446        /**
447         * Generates generic type text with links to classifiers.
448         * @param eGenericType
449         * @param accumulator 
450         */
451        protected void genericType(EGenericType eGenericType, EClassifier contextClassifier, Consumer<String> accumulator, ProgressMonitor monitor) {
452                if (eGenericType == null) {
453                        accumulator.accept("void");
454                } else {
455                        ETypeParameter eTypeParameter = eGenericType.getETypeParameter();
456                        if (eTypeParameter != null) {
457                                accumulator.accept(labelProvider.apply(eTypeParameter, eTypeParameter.getName()));
458                        } else if (eGenericType.getEClassifier() != null) {
459                                accumulator.accept(link(eGenericType.getEClassifier(), contextClassifier));
460                                genericTypeArguments(eGenericType, contextClassifier, accumulator, monitor);
461                        } else {
462                                accumulator.accept("?");
463                                if (eGenericType.getELowerBound() != null) {
464                                        accumulator.accept(" super ");
465                                        genericType(eGenericType.getELowerBound(), contextClassifier, accumulator, monitor);
466                                } else if (eGenericType.getEUpperBound() != null) {
467                                        accumulator.accept(" extends ");
468                                        genericType(eGenericType.getEUpperBound(), contextClassifier, accumulator, monitor);
469                                }
470                        }
471                }
472        }
473        
474        /**
475         * @param eClassifier
476         * @return Relative path to the argument {@link EClassifier} or null if the classifier is not part of the documentation resource set.
477         */
478        protected String path(EClassifier eClassifier, EClassifier contextClassifier) {
479                if (!elementPredicate.test(eClassifier)) {
480                        return null;
481                }
482                // TODO - resolution of external eClassifiers for federated/hierarchical documentation - from the adapter factory.
483                Resource targetResource = eClassifier.eResource();
484                if (targetResource == null) {
485                        return null;
486                }
487                ResourceSet targetResourceSet = targetResource.getResourceSet();
488                if (targetResourceSet != eObject.eResource().getResourceSet()) {
489                        return null;
490                }               
491
492                String targetEPackagePath = encodeEPackage(eClassifier.getEPackage());
493                if (Util.isBlank(targetEPackagePath)) {
494                        return null;
495                }
496                
497                String targetPath = targetEPackagePath + "/" + eClassifier.getName() + ".html";
498                String thisPath = null;
499                if (contextClassifier == null) {
500                        if (eObject instanceof EClassifier) {
501                                contextClassifier = (EClassifier) eObject;
502                        } else if (eObject.eContainer() instanceof EClassifier) {
503                                contextClassifier = (EClassifier) eObject.eContainer();
504                        } else if (eObject.eContainer() instanceof EOperation) {
505                                contextClassifier = (EClassifier) eObject.eContainer().eContainer();
506                        } 
507                }
508                        
509                if (contextClassifier != null) {        
510                        thisPath = encodeEPackage(contextClassifier.getEPackage()) + "/" + contextClassifier.getName() + ".html";
511                } else if (eObject instanceof EPackage) {
512                        thisPath = encodeEPackage(((EPackage) eObject)) + "/package-summary.html";                                      
513                }
514                
515                if (thisPath == null) {
516                        return null;
517                }
518                
519                URI base = URI.createURI(context.getString(Context.BASE_URI_PROPERTY, "tmp://base/doc/"));
520                URI target = URI.createURI(targetPath).resolve(base);
521                URI source = URI.createURI(thisPath).resolve(base);
522                URI relativeTarget = target.deresolve(source, true, true, true);
523                return relativeTarget.toString();               
524        }
525        
526        /**
527         * @return Link to {@link EClassifier} if it is part of the doc or plain text if it is not.
528         */
529        protected String link(EClassifier eClassifier, EClassifier contextClassifier) {
530                String path = path(eClassifier, contextClassifier);
531                String label = labelProvider.apply(eClassifier, eClassifier.getName());
532                return Util.isBlank(path) ? label : "<a href=\"" + path + "\">" + label + "</a>";
533        }
534        
535        /**
536         * @return Link to {@link EClassifier} if it is part of the doc or plain text if it is not.
537         */
538        protected String link(EStructuralFeature feature, EClassifier contextClassifier) {
539                String path = path(feature.getEContainingClass(), contextClassifier);
540                String fragment = "#" + feature.eClass().getName() + "-" + feature.getName();
541                path = Util.isBlank(path) ? fragment : path + fragment;
542                return  "<a href=\"" + path + "\">" + labelProvider.apply(feature, feature.getName()) + "</a>";
543        }
544
545        protected void genericTypeArguments(EGenericType eGenericType, EClassifier contextClassifier, Consumer<String> accumulator, ProgressMonitor monitor) {
546                Iterator<EGenericType> it = eGenericType.getETypeArguments().iterator();
547                if (it.hasNext()) {
548                        accumulator.accept("&lt;");
549                        while (it.hasNext()) {
550                                genericType(it.next(), contextClassifier, accumulator, monitor);
551                                if (it.hasNext()) {
552                                        accumulator.accept(",");
553                                }
554                        }
555                        accumulator.accept("&gt;");
556                }
557        }
558        
559        /**
560         * Encodes ePackage path.
561         * @param ePackage
562         * @return
563         */
564        public String encodeEPackage(EPackage ePackage) {
565                return ePackagePathComputer == null ? Hex.encodeHexString(ePackage.getNsURI().getBytes(StandardCharsets.UTF_8)) : ePackagePathComputer.apply(ePackage);
566//
567//              
568//              String ret = null;
569//                              
570//              for (EPackage p = ePackage; p != null; p = p.getESuperPackage()) {
571//                      String segment = ePackagePathComputer == null ? Hex.encodeHexString(p.getNsURI().getBytes(StandardCharsets.UTF_8)) : ePackagePathComputer.apply(p);
572//                      if (ret == null) {
573//                              ret = segment;
574//                      } else {
575//                              ret = segment + "/" + ret;
576//                      }
577//              }
578//              
579//              return ret;
580        }
581        
582        /**
583         * Adds textual content.
584         * @param content
585         */
586        protected static void addContent(Action action, String content) {
587                Text text = ContentFactory.eINSTANCE.createText();
588                text.setContent(content);
589                action.getContent().add(text);
590        }
591        
592        /**
593         * Filters the collection retaining only model elements which shall be documented.
594         * @param <M>
595         * @param elements
596         * @return
597         */
598        protected <M extends EModelElement> List<M> retainDocumentable(Collection<M> elements) {
599                return elements.stream().filter(elementPredicate).collect(Collectors.toList());
600        }
601
602        protected static Class<?> getInstanceClass(EClassifier eClassifier, java.util.function.Function<String, Object> ePackageResolver) {
603                Class<?> instanceClass = eClassifier.getInstanceClass();
604                if (instanceClass == null) {
605                        EPackage registeredPackage = getRegisteredPackage(eClassifier, ePackageResolver);
606                        if (registeredPackage != null) {
607                                EClassifier registeredClassifier = registeredPackage.getEClassifier(eClassifier.getName());
608                                if (registeredClassifier != null) {
609                                        instanceClass = registeredClassifier.getInstanceClass();
610                                }
611                        }
612                }
613                return instanceClass;
614        }
615        
616        private static EPackage getRegisteredPackage(EClassifier eObject, java.util.function.Function<String, Object> ePackageResolver) {
617                String nsURI = eObject.getEPackage().getNsURI();
618                Object value = ePackageResolver.apply(nsURI);
619                if (value instanceof EPackage) {
620                        return (EPackage) value;
621                }
622                if (value instanceof EPackage.Descriptor) {
623                        return Objects.requireNonNull(((EPackage.Descriptor) value).getEPackage(), "EPackage is null for " + nsURI);  
624                }
625                
626                if (value instanceof EPackage) {
627                        return (EPackage) value;
628                }
629                return null;
630        }       
631        
632        
633}