001package org.nasdanika.html.model.app.graph.emf; 002 003import java.util.Collection; 004 005import org.eclipse.emf.common.util.URI; 006import org.eclipse.emf.ecore.EClass; 007import org.eclipse.emf.ecore.EObject; 008import org.eclipse.emf.ecore.EOperation; 009import org.eclipse.emf.ecore.EReference; 010import org.nasdanika.common.ProgressMonitor; 011import org.nasdanika.common.Supplier; 012import org.nasdanika.graph.Node; 013import org.nasdanika.graph.emf.EObjectNode; 014import org.nasdanika.graph.emf.EOperationConnection; 015import org.nasdanika.graph.emf.EReferenceConnection; 016import org.nasdanika.graph.emf.QualifiedConnection; 017import org.nasdanika.graph.processor.ConnectionProcessorConfig; 018import org.nasdanika.html.model.app.Label; 019import org.nasdanika.html.model.app.Link; 020import org.nasdanika.html.model.app.graph.WidgetFactory; 021 022public class ConnectionProcessor { 023 024 protected URI sourceURI; 025 protected URI targetURI; 026 protected ConnectionProcessorConfig<WidgetFactory, WidgetFactory> config; 027 private boolean compactPath; 028 029 /** 030 * 031 * @param config 032 * @param compactPath if true then reference and operation paths are constructed using reference/operation id's and r or o prefix respectively. 033 */ 034 public ConnectionProcessor(ConnectionProcessorConfig<WidgetFactory, WidgetFactory> config, boolean compactPath) { 035 this.config = config; 036 this.compactPath = compactPath; 037 038 config.getSourceEndpoint().thenAccept(se -> config.setTargetHandler(createTargetHandler(se))); 039 config.getTargetEndpoint().thenAccept(te -> config.setSourceHandler(createSourceHandler(te))); 040 } 041 042 protected WidgetFactory createTargetHandler(WidgetFactory sourceEndpoint) { 043 return new WidgetFactory() { 044 045 @Override 046 public void resolve(URI base, ProgressMonitor progressMonitor) { 047 targetURI = base; 048 } 049 050 private URI resolveBase(URI base) { 051 if (base == null) { 052 return targetURI; 053 } 054 if (base.isRelative() && targetURI != null && !targetURI.isRelative()) { 055 return base.resolve(targetURI); 056 } 057 return base; 058 } 059 060 @SuppressWarnings("unchecked") 061 @Override 062 public String selectString(Object selector, URI base, ProgressMonitor progressMonitor) { 063 if (selector instanceof Selector) { 064 return select((Selector<String>) selector, base, progressMonitor); 065 } 066 return sourceEndpoint.selectString(selector, resolveBase(base), progressMonitor); 067 } 068 069 @Override 070 public Object select(Object selector, URI base, ProgressMonitor progressMonitor) { 071 if (selector instanceof Selector) { 072 return select((Selector<?>) selector, base, progressMonitor); 073 } 074 return sourceEndpoint.select(selector, resolveBase(base), progressMonitor); 075 } 076 077 @Override 078 public <T> T select(Selector<T> selector, URI base, ProgressMonitor progressMonitor) { 079 if (selector instanceof ConnectionSelector) { 080 return selector.select(this, resolveBase(base), progressMonitor); 081 } 082 return sourceEndpoint.select(selector, resolveBase(base), progressMonitor); 083 } 084 085 @Override 086 public String createLinkString(URI base, ProgressMonitor progressMonitor) { 087 return sourceEndpoint.createLinkString(resolveBase(base), progressMonitor); 088 } 089 090 @Override 091 public Object createLink(URI base, ProgressMonitor progressMonitor) { 092 return sourceEndpoint.createLink(resolveBase(base), progressMonitor); 093 } 094 095 @Override 096 public Label createHelpDecorator(URI base, ProgressMonitor progressMonitor) { 097 return sourceEndpoint.createHelpDecorator(resolveBase(base), progressMonitor); 098 } 099 100 @Override 101 public Supplier<Collection<Label>> createLabelsSupplier() { 102 return sourceEndpoint.createLabelsSupplier().then(labels -> { 103 for (Label label : labels) { 104 if (label instanceof Link) { 105 ((Link) label).rebase(targetURI, sourceURI); 106 } 107 } 108 return labels; 109 }); 110 } 111 112 @Override 113 public String createLabelString(ProgressMonitor progressMonitor) { 114 return sourceEndpoint.createLabelString(progressMonitor); 115 } 116 117 @Override 118 public Object createLabel(ProgressMonitor progressMonitor) { 119 return sourceEndpoint.createLabel(progressMonitor); 120 } 121 122 }; 123 124 } 125 126 protected WidgetFactory createSourceHandler(WidgetFactory targetEndpoint) { 127 return new WidgetFactory() { 128 129 @Override 130 public void resolve(URI base, ProgressMonitor progressMonitor) { 131 sourceURI = base; 132 QualifiedConnection<?> conn = (QualifiedConnection<?>) config.getElement(); 133 String path = conn.getPath(); 134 Node source = config.getElement().getSource(); 135 EClass eClass = null; 136 if (source instanceof EObjectNode) { 137 EObject eObject = ((EObjectNode) source).get(); 138 eClass = eObject == null ? null : eObject.eClass(); 139 } 140 141 if (conn instanceof EReferenceConnection) { 142 EReference eRef = ((EReferenceConnection) conn).getReference(); 143 if (eRef.isContainment()) { 144 String uriStr; 145 if (compactPath && eClass != null) { 146 uriStr = "r" + Integer.toString(eClass.getFeatureID(eRef), Character.MAX_RADIX); 147 } else { 148 uriStr = "references/" + eRef.getName(); 149 } 150 if (path != null) { 151 uriStr += "/" + path + "/"; 152 } 153 URI refURI = URI.createURI(uriStr); 154 targetEndpoint.resolve(refURI.resolve(base), progressMonitor); 155 } 156 } else if (conn instanceof EOperationConnection) { 157 EOperation eOp = ((EOperationConnection) conn).getOperation(); 158 String uriStr; 159 if (compactPath && eClass != null) { 160 uriStr = "o" + Integer.toString(eClass.getOperationID(eOp), Character.MAX_RADIX); 161 } else { 162 uriStr = "operations/" + eOp.getName(); 163 } 164 if (path != null) { 165 uriStr += "/" + path + "/"; 166 } 167 URI refURI = URI.createURI(uriStr); 168 targetEndpoint.resolve(refURI.resolve(base), progressMonitor); 169 } 170 } 171 172 private URI resolveBase(URI base) { 173 if (base == null) { 174 return sourceURI; 175 } 176 if (base.isRelative() && sourceURI != null && !sourceURI.isRelative()) { 177 return base.resolve(sourceURI); 178 } 179 return base; 180 } 181 182 @SuppressWarnings("unchecked") 183 @Override 184 public String selectString(Object selector, URI base, ProgressMonitor progressMonitor) { 185 if (selector instanceof Selector) { 186 return select((Selector<String>) selector, base, progressMonitor); 187 } 188 return targetEndpoint.selectString(selector, resolveBase(base), progressMonitor); 189 } 190 191 @Override 192 public Object select(Object selector, URI base, ProgressMonitor progressMonitor) { 193 if (selector instanceof Selector) { 194 return select((Selector<?>) selector, base, progressMonitor); 195 } 196 return targetEndpoint.select(selector, resolveBase(base), progressMonitor); 197 } 198 199 @Override 200 public <T> T select(Selector<T> selector, URI base, ProgressMonitor progressMonitor) { 201 if (selector instanceof ConnectionSelector) { 202 return selector.select(this, resolveBase(base), progressMonitor); 203 } 204 return targetEndpoint.select(selector, resolveBase(base), progressMonitor); 205 } 206 207 @Override 208 public String createLinkString(URI base, ProgressMonitor progressMonitor) { 209 return targetEndpoint.createLinkString(resolveBase(base), progressMonitor); 210 } 211 212 @Override 213 public Object createLink(URI base, ProgressMonitor progressMonitor) { 214 return targetEndpoint.createLink(resolveBase(base), progressMonitor); 215 } 216 217 @Override 218 public Label createHelpDecorator(URI base, ProgressMonitor progressMonitor) { 219 return targetEndpoint.createHelpDecorator(resolveBase(base), progressMonitor); 220 } 221 222 @Override 223 public Supplier<Collection<Label>> createLabelsSupplier() { 224 return targetEndpoint.createLabelsSupplier().then(labels -> { 225 for (Label label : labels) { 226 if (label instanceof Link) { 227 ((Link) label).rebase(targetURI, sourceURI); 228 } 229 } 230 return labels; 231 }); 232 } 233 234 @Override 235 public String createLabelString(ProgressMonitor progressMonitor) { 236 return targetEndpoint.createLabelString(progressMonitor); 237 } 238 239 @Override 240 public Object createLabel(ProgressMonitor progressMonitor) { 241 return targetEndpoint.createLabel(progressMonitor); 242 } 243 244 }; 245 } 246 247}