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}