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