001package org.nasdanika.html.ecore;
002
003import java.nio.charset.StandardCharsets;
004import java.security.MessageDigest;
005import java.security.NoSuchAlgorithmException;
006import java.util.function.BiFunction;
007import java.util.function.Function;
008import java.util.function.Predicate;
009
010import org.apache.commons.codec.binary.Hex;
011import org.eclipse.emf.common.util.EList;
012import org.eclipse.emf.ecore.EClass;
013import org.eclipse.emf.ecore.EClassifier;
014import org.eclipse.emf.ecore.EGenericType;
015import org.eclipse.emf.ecore.EModelElement;
016import org.eclipse.emf.ecore.ENamedElement;
017import org.eclipse.emf.ecore.EOperation;
018import org.eclipse.emf.ecore.EPackage;
019import org.eclipse.emf.ecore.EParameter;
020import org.nasdanika.common.Context;
021import org.nasdanika.common.NasdanikaException;
022import org.nasdanika.common.ProgressMonitor;
023import org.nasdanika.html.Fragment;
024import org.nasdanika.html.HTMLFactory;
025import org.nasdanika.html.Tag;
026import org.nasdanika.html.TagName;
027import org.nasdanika.html.bootstrap.Table;
028import org.nasdanika.html.model.app.Action;
029import org.nasdanika.html.model.app.AppFactory;
030import org.nasdanika.html.model.app.SectionStyle;
031
032public class EOperationActionSupplier extends ETypedElementActionSupplier<EOperation> implements EcoreActionSupplier  {
033
034        public EOperationActionSupplier(
035                        EOperation value, 
036                        Context context, 
037                        java.util.function.Function<EPackage,String> ePackagePathComputer,
038                        Predicate<EModelElement> elementPredicate,
039                        BiFunction<ENamedElement, String, String> labelProvider) {
040                super(value, context, ePackagePathComputer, elementPredicate, labelProvider);
041        }
042        
043        @Override
044        public Action execute(EClass contextEClass, ProgressMonitor progressMonitor) {
045                try {
046                        Action action = super.execute(contextEClass, progressMonitor);
047                        action.setSectionStyle(SectionStyle.HEADER);
048                        
049                        EClass eContainingClass = eObject.getEContainingClass();
050                        
051                        EList<Action> sections = action.getSections();          
052                        
053                        if (!eObject.getEParameters().isEmpty()) {
054                                Action parametersCategory = AppFactory.eINSTANCE.createAction();
055                                parametersCategory.setText("Parameters");
056                                sections.add(parametersCategory);
057                                EList<Action> parameters = parametersCategory.getSections();
058                                
059                                // Creating a digest of parameter types to make the id shorter.
060                                MessageDigest md = MessageDigest.getInstance("SHA-256");
061                                
062                                for (EParameter ep: eObject.getEParameters()) {
063                                        EClassifier type = ep.getEType();
064                                        String typeStr = type.eClass().getName() + "-" + encodeEPackage(type.getEPackage()) + "-" + type.getName() + ",";
065                                        md.update(typeStr.getBytes(StandardCharsets.UTF_8));
066                                        
067                                        parameters.add(adaptChild(ep).execute(contextEClass, progressMonitor));                         
068                                }
069                        }
070                        
071                        String signature = eOperationSignature(eObject, this::encodeEPackage);
072                        
073                        StringBuilder idBuilder = new StringBuilder(encodeEPackage(eContainingClass.getEPackage()))
074                                        .append("-")
075                                        .append(eContainingClass.getName())
076                                        .append("-")
077                                        .append(signature);
078                        
079                        action.setId(idBuilder.toString());
080                        action.setName(signature);
081                        
082                        // Exceptions
083                        EList<EGenericType> eGenericExceptions = eObject.getEGenericExceptions();
084                        if (!eGenericExceptions.isEmpty()) {
085                                HTMLFactory htmlFactory = context.get(HTMLFactory.class);
086                                Fragment gstf = htmlFactory.fragment(TagName.h3.create("Exceptions"));
087        
088                                Tag list = TagName.ul.create();
089                                gstf.content(list);
090                                
091                                for (EGenericType genericException: eGenericExceptions) {
092                                        Tag listItem = TagName.li.create();
093                                        list.content(listItem);
094                                        genericType(genericException, contextEClass, listItem.getContent()::add, progressMonitor);
095                                }
096                                addContent(action, gstf.toString());
097                        }                               
098                        
099                        return action;
100                } catch (NoSuchAlgorithmException e) {
101                        throw new NasdanikaException(e);
102                }
103        }
104        
105        public static String eOperationSignature(EOperation eOperation, Function<EPackage, String> ePackageEncoder) throws NoSuchAlgorithmException {           
106                StringBuilder signatureBuilder = new StringBuilder(eOperation.eClass().getName())
107                                .append("-")
108                                .append(eOperation.getName());
109                
110                if (!eOperation.getEParameters().isEmpty()) {
111                        // Creating a digest of parameter types to make the id shorter.
112                        MessageDigest md = MessageDigest.getInstance("SHA-256");
113                        
114                        for (EParameter ep: eOperation.getEParameters()) {
115                                EClassifier type = ep.getEType();
116                                String typeStr = type.eClass().getName() + "-" + ePackageEncoder.apply(type.getEPackage()) + "-" + type.getName() + ",";
117                                md.update(typeStr.getBytes(StandardCharsets.UTF_8));
118                        }
119                        signatureBuilder.append("-").append(Hex.encodeHexString(md.digest()));                  
120                }
121
122                return signatureBuilder.toString();
123        }
124        
125        @Override
126        protected Table propertiesTable(EClass contextEClass, ProgressMonitor monitor) {
127                Table table = super.propertiesTable(contextEClass, monitor);
128                if (contextEClass != null) {
129                                addRow(table, "Declaring class").add(link(eObject.getEContainingClass(), contextEClass));
130                }
131                return table;
132        }
133                
134}