001 package com.hammurapi.review; 002 003 import java.net.URL; 004 import java.net.URLClassLoader; 005 import java.util.ArrayList; 006 import java.util.Iterator; 007 import java.util.List; 008 import java.util.concurrent.Callable; 009 import java.util.concurrent.Executor; 010 import java.util.concurrent.Future; 011 import java.util.logging.Logger; 012 013 import org.eclipse.emf.common.util.TreeIterator; 014 015 import com.hammurapi.config.Factory; 016 import com.hammurapi.config.Path; 017 import com.hammurapi.config.bootstrap.ConfigurationException; 018 import com.hammurapi.config.bootstrap.Destroyable; 019 import com.hammurapi.config.bootstrap.FactoryClosure; 020 import com.hammurapi.config.runtime.CompositeDestroyable; 021 import com.hammurapi.config.runtime.ConfigurationContext; 022 import com.hammurapi.config.runtime.DestroyableSink; 023 import com.hammurapi.config.runtime.FactoryConfig; 024 import com.hammurapi.convert.ConvertingService; 025 import com.hammurapi.reasoning.ExceptionHandler; 026 import com.hammurapi.reasoning.ForwardReasoningSession; 027 import com.hammurapi.reasoning.ForwardReasoningSessionFactory; 028 import com.hammurapi.reasoning.ReasoningException; 029 import com.hammurapi.util.InlineExecutor; 030 import com.hammurapi.util.SingletonChainingContext; 031 import com.hammurapi.util.concurrent.NonBlockingFutureTask; 032 033 /** 034 * This class performs reviews invoking other review framework components. 035 * @author Pavel Vlasov 036 * 037 */ 038 public abstract class ReviewDriverBase implements Callable<Object>, com.hammurapi.config.runtime.Component<Component> { 039 040 private static final Logger logger = Logger.getLogger(ReviewDriverBase.class.getName()); 041 042 private Executor executor; 043 private ConfigurationContext<Component> context; 044 045 @Override 046 public void init(ConfigurationContext<Component> context) throws ConfigurationException { 047 executor = context.lookup(Executor.class); 048 if (executor==null) { 049 executor = InlineExecutor.INSTANCE; 050 } 051 this.context = context; 052 } 053 054 /** 055 * Loads component definition resource and executes review. 056 * @param componentConfig 057 * @throws ConfigurationException 058 */ 059 @SuppressWarnings("unchecked") 060 @Override 061 public Object call() throws Exception { 062 CompositeDestroyable destroyableSink = new CompositeDestroyable(); 063 try { 064 // Create reporters 065 List<Reporter<Object>> reporters = new ArrayList<Reporter<Object>>(); 066 for (Factory rf: context.getDefinition().getReporter()) { 067 FactoryClosure<Object> rfr = rf.create(context.getFactoryConfig()); 068 logger.fine("Creating a reporter"); 069 reporters.add((Reporter<Object>) rfr.create()); 070 destroyableSink.addDestroyable(rfr.getDestroyable()); 071 } 072 073 try { 074 List<Future<Object>> tasks = new ArrayList<Future<Object>>(); 075 // Review modules 076 for (Module module: context.getDefinition().getModule()) { 077 NonBlockingFutureTask<Object> task = new NonBlockingFutureTask<Object>(createModuleTask(module, reporters, context.getFactoryConfig(), destroyableSink, executor)); 078 tasks.add(task); 079 executor.execute(task); 080 } 081 082 for (Future<Object> task: tasks) { 083 try { 084 task.get(); 085 } catch (Exception e) { 086 for (Reporter r: reporters) { 087 r.onException(e); 088 } 089 } 090 } 091 } finally { 092 for (Reporter<Object> r: reporters) { 093 r.close(); 094 } 095 } 096 } finally { 097 destroyableSink.destroy(); 098 } 099 return null; 100 } 101 102 private Callable<Object> createModuleTask( 103 final Module module, 104 final List<Reporter<Object>> reporters, 105 final FactoryConfig factoryConfig, 106 final DestroyableSink destroyableSink, 107 final Executor executor) { 108 109 logger.fine("Creating a module task for "+module.getName()); 110 111 return new Callable<Object>() { 112 113 @SuppressWarnings("unchecked") 114 @Override 115 public Object call() throws Exception { 116 logger.fine("Executing module task for "+module.getName()); 117 118 // Classpath 119 List<URL> pathElements = new ArrayList<URL>(); 120 for (Path path: module.getClassPath()) { 121 pathElements.addAll(path.getUrls(factoryConfig.getContextUrl(), factoryConfig.getTokenSource())); 122 } 123 124 ClassLoader classLoader = factoryConfig.getClassLoader(); 125 if (classLoader==null) { 126 classLoader = getClass().getClassLoader(); 127 } 128 129 if (!pathElements.isEmpty()) { 130 logger.fine("Constructing module URL classloader from "+pathElements); 131 classLoader = new URLClassLoader(pathElements.toArray(new URL[pathElements.size()]), classLoader); 132 } 133 134 FactoryConfig moduleFactoryConfig = (FactoryConfig) factoryConfig.clone(); 135 moduleFactoryConfig.setClassLoader(classLoader); 136 137 final List<ForwardReasoningSessionFactory<Object>> inspectorSetSessionFactories = new ArrayList<ForwardReasoningSessionFactory<Object>>(); 138 for (InspectorSet inspectorSet: module.getInspectorSet()) { 139 inspectorSetSessionFactories.add(createInspectorSetSessionFactory(inspectorSet, moduleFactoryConfig)); 140 } 141 142 try { 143 logger.fine("Reviewing module sources: "+module.getSource().size()); 144 for (Factory sf: module.getSource()) { 145 logger.fine("Reviewing module source"); 146 final CompositeObservationSink observationSink = new CompositeObservationSink(); 147 for (Reporter<Object> r: reporters) { 148 observationSink.addSink(r.createObservationSink(module)); 149 } 150 151 FactoryConfig modelConfig = (FactoryConfig) moduleFactoryConfig.clone(); 152 modelConfig.setContext(new SingletonChainingContext<ObservationSink>(ObservationSink.class, observationSink, modelConfig.getContext())); 153 FactoryClosure<Object> sfr = sf.create(modelConfig); 154 Object model = sfr.create(); 155 module.getModel().add(model); 156 destroyableSink.addDestroyable(sfr.getDestroyable()); 157 158 List<Future<Object>> tasks = new ArrayList<Future<Object>>(); 159 Iterable<Object> modelIterable = ConvertingService.convert(model, Iterable.class); 160 if (modelIterable==null) { 161 Warning warning = ReviewFactory.eINSTANCE.createWarning(); 162 warning.setMessage(model.getClass()+" cannot be converted to Iterable"); 163 observationSink.consumeObservation(warning); 164 } else { 165 ExceptionHandler exceptionHandler = new ExceptionHandler() { 166 167 @Override 168 public void handleException(Exception e) throws Exception { 169 Warning warning = ReviewFactory.eINSTANCE.createWarning(); 170 warning.setMessage("Exception during inspector execution"); 171 warning.setCause(e); 172 observationSink.consumeObservation(warning); 173 } 174 }; 175 List<ForwardReasoningSession<Object>> moduleSessions = new ArrayList<ForwardReasoningSession<Object>>(); 176 for (ForwardReasoningSessionFactory<Object> issf: inspectorSetSessionFactories) { 177 logger.fine("Creating module session"); 178 ForwardReasoningSession<Object> session = issf.createSession(null); 179 session.setExceptionHandler(exceptionHandler); 180 moduleSessions.add(session); // TODO - session properties. 181 } 182 try { 183 // Collect observations from the model loading 184 Iterator<Object> modelIterator = modelIterable.iterator(); 185 while (modelIterator.hasNext()) { 186 Object modelElement = modelIterator.next(); 187 if (modelElement instanceof LanguageElement) { 188 for (Observation observation: ((LanguageElement) modelElement).getObservations()) { 189 observationSink.consumeObservation(observation); 190 } 191 } 192 } 193 194 // Give the model to inspectors. 195 modelIterator = modelIterable.iterator(); 196 while (modelIterator.hasNext()) { 197 review(modelIterator, tasks, executor, moduleSessions, inspectorSetSessionFactories, observationSink); 198 } 199 200 // Collect observations from sessions 201 for (ForwardReasoningSession<Object> frs: moduleSessions) { 202 frs.executeRules(); 203 for (Object fact: frs.getObjects()) { 204 if (fact instanceof Observation) { 205 observationSink.consumeObservation((Observation) fact); 206 } 207 } 208 } 209 210 } finally { 211 for (ForwardReasoningSession<Object> frs: moduleSessions) { 212 frs.close(); 213 } 214 } 215 } 216 217 // Wait for review tasks to finish 218 for (Future<Object> task: tasks) { 219 task.get(); 220 } 221 222 // Close sinks 223 observationSink.close(); 224 } 225 226 return null; 227 } finally { 228 for (ForwardReasoningSessionFactory<Object> issf: inspectorSetSessionFactories) { 229 if (issf instanceof Destroyable) { 230 ((Destroyable) issf).destroy(); 231 } 232 } 233 } 234 } 235 236 }; 237 } 238 239 /** 240 * Reviews model element, possibly in a different thread. 241 * @param modelElement 242 * @param inspectorSetSessionFactories 243 * @param moduleSessions 244 * @param counter 245 * @param executor 246 * @param observationSinks 247 * @throws ReasoningException 248 */ 249 @SuppressWarnings("unchecked") 250 private void review( 251 Iterator<Object> modelIterator, 252 final List<Future<Object>> tasks, 253 final Executor executor, 254 List<ForwardReasoningSession<Object>> sessions, 255 final List<ForwardReasoningSessionFactory<Object>> inspectorSetSessionFactories, 256 final ObservationSink observationSink) { 257 258 final Object modelElement = modelIterator.next(); 259 if (modelElement!=null) { 260 if (modelIterator instanceof TreeIterator<?> && modelElement.getClass().getAnnotation(Fork.class)!=null) { 261 // Reviewing model element in a separate thread 262 final Iterable<Object> meIterable = ConvertingService.convert(modelElement, Iterable.class); 263 if (meIterable!=null) { 264 ((TreeIterator<?>) modelIterator).prune(); 265 Runnable reviewTask = new Runnable() { 266 267 @Override 268 public void run() { 269 try { 270 List<ForwardReasoningSession<Object>> meSessions = new ArrayList<ForwardReasoningSession<Object>>(); 271 for (ForwardReasoningSessionFactory<Object> issf: inspectorSetSessionFactories) { 272 meSessions.add(issf.createSession(null)); // TODO - session properties. 273 } 274 try { 275 Iterator<Object> modelIterator = meIterable.iterator(); 276 while (modelIterator.hasNext()) { 277 review(modelIterator, tasks, executor, meSessions, inspectorSetSessionFactories, observationSink); 278 } 279 // Collect observations 280 for (ForwardReasoningSession<Object> frs: meSessions) { 281 frs.executeRules(); 282 for (Object fact: frs.getObjects()) { 283 if (fact instanceof Observation) { 284 observationSink.consumeObservation((Observation) fact); 285 } 286 } 287 } 288 289 } finally { 290 for (ForwardReasoningSession<Object> frs: meSessions) { 291 frs.close(); 292 } 293 } 294 } catch (Exception e) { 295 Warning warning = ReviewFactory.eINSTANCE.createWarning(); 296 warning.setMessage("Exception: "+e); 297 warning.setCause(e); 298 warning.setSource(ConvertingService.convert(modelElement, LanguageElement.class)); 299 } 300 } 301 302 }; 303 304 executor.execute(new NonBlockingFutureTask<Object>(reviewTask, Boolean.TRUE)); 305 return; 306 } 307 } 308 309 for (ForwardReasoningSession<Object> frs: sessions) { 310 try { 311 frs.put(modelElement); 312 } catch (ReasoningException e) { 313 Warning warning = ReviewFactory.eINSTANCE.createWarning(); 314 warning.setMessage("Exception: "+e); 315 warning.setCause(e); 316 warning.setSource(ConvertingService.convert(modelElement, LanguageElement.class)); 317 } 318 } 319 } 320 } 321 322 protected abstract ForwardReasoningSessionFactory<Object> createInspectorSetSessionFactory(InspectorSet inspectorSet, FactoryConfig moduleFactoryConfig) throws ConfigurationException, ReasoningException; 323 }