| /** |
| * |
| * Copyright (c) 2011, 2016 - Loetz GmbH&Co.KG (69115 Heidelberg, Germany) |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Christophe Loetz (Loetz GmbH&Co.KG) - initial implementation |
| * |
| * |
| * This copyright notice shows up in the generated Java code |
| * |
| */ |
| |
| package org.eclipse.osbp.xtext.datainterchange.jvmmodel |
| |
| import com.vaadin.server.ClientConnector.AttachEvent |
| import com.vaadin.server.ClientConnector.AttachListener |
| import com.vaadin.server.ClientConnector.DetachEvent |
| import com.vaadin.server.ClientConnector.DetachListener |
| import com.vaadin.ui.Button |
| import com.vaadin.ui.CssLayout |
| import com.vaadin.ui.Label |
| import com.vaadin.ui.VerticalLayout |
| import java.io.OutputStream |
| import java.net.URL |
| import java.util.ArrayList |
| import java.util.HashMap |
| import java.util.Locale |
| import java.util.Map |
| import java.util.concurrent.ExecutorService |
| import javax.inject.Inject |
| import javax.persistence.EntityManager |
| import javax.xml.transform.Transformer |
| import javax.xml.transform.TransformerFactory |
| import org.eclipse.e4.core.contexts.IEclipseContext |
| import org.eclipse.e4.ui.di.Focus |
| import org.eclipse.e4.ui.model.application.MApplication |
| import org.eclipse.osbp.core.api.persistence.IPersistenceService |
| import org.eclipse.osbp.datainterchange.api.IDataInterchange |
| import org.eclipse.osbp.dsl.entity.xtext.extensions.ModelExtensions |
| import org.eclipse.osbp.osgi.hybrid.api.AbstractHybridVaaclipseView |
| import org.eclipse.osbp.runtime.common.event.EventDispatcherEvent |
| import org.eclipse.osbp.runtime.common.event.IEventDispatcher |
| import org.eclipse.osbp.ui.api.e4.IE4Focusable |
| import org.eclipse.osbp.ui.api.metadata.IDSLMetadataService |
| import org.eclipse.osbp.ui.api.user.IUser |
| import org.eclipse.osbp.xtext.datainterchange.DataInterchange |
| import org.eclipse.osbp.xtext.datainterchange.DataInterchangeBean |
| import org.eclipse.osbp.xtext.datainterchange.DataInterchangeBlobMapping |
| import org.eclipse.osbp.xtext.datainterchange.DataInterchangeFileCSV |
| import org.eclipse.osbp.xtext.datainterchange.DataInterchangeFileEDI |
| import org.eclipse.osbp.xtext.datainterchange.DataInterchangeFileXML |
| import org.eclipse.osbp.xtext.datainterchange.DataInterchangePackage |
| import org.eclipse.osbp.xtext.datainterchange.EntityManagerMode |
| import org.eclipse.osbp.xtext.datainterchange.common.WorkerThreadRunnable |
| import org.eclipse.osbp.xtext.entitymock.common.IEntityImportInitializationListener |
| import org.eclipse.osbp.xtext.i18n.DSLOutputConfigurationProvider |
| import org.eclipse.xtext.common.types.JvmDeclaredType |
| import org.eclipse.xtext.common.types.JvmField |
| import org.eclipse.xtext.common.types.JvmGenericType |
| import org.eclipse.xtext.common.types.JvmVisibility |
| import org.eclipse.xtext.naming.IQualifiedNameProvider |
| import org.eclipse.xtext.xbase.jvmmodel.AbstractModelInferrer |
| import org.eclipse.xtext.xbase.jvmmodel.IJvmDeclaredTypeAcceptor |
| import org.eclipse.xtext.xbase.jvmmodel.JvmTypesBuilder |
| import org.osgi.framework.BundleEvent |
| import org.osgi.framework.BundleListener |
| import org.slf4j.Logger |
| import org.eclipse.osbp.ui.api.customfields.IBlobService |
| |
| /** |
| * <p> |
| * Data Interchange Repository Domain Specific Language |
| * This inferrer infers models of extension .data and generates code to be used by any data interchanging process |
| * to facilitate the communication with external data sources and drains. |
| * </p> |
| * |
| * @author Joerg Riegel |
| */ |
| |
| class DataDSLJvmModelInferrer extends AbstractModelInferrer { |
| |
| @Inject extension JvmTypesBuilder |
| @Inject extension IQualifiedNameProvider |
| @Inject extension DataDSLModelGenerator dg |
| @Inject extension ModelExtensions |
| |
| /* ramp up NTHREADS and threads are finished start more but up to this limit */ |
| var NTHREADS = 10; |
| |
| /** |
| * infer model on package base. Will be called for every defined package. |
| * |
| * @param dataInterchangePackage |
| * An instance of {@link DataInterchangePackage} |
| * @param acceptor |
| * the xtext acceptor interface |
| * @param isPreIndexingPhase |
| * true if in preindexing phase |
| */ |
| def dispatch void infer(DataInterchangePackage dataInterchangePackage, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) { |
| dataInterchangePackage.generatePckgName(acceptor) |
| // create a view |
| var cls = dataInterchangePackage.toClass(dataInterchangePackage.name.toString.concat("TriggerView")); |
| cls.simpleName = cls.simpleName.toFirstUpper |
| acceptor.accept(cls, |
| [ |
| superTypes += _typeReferenceBuilder.typeRef(AbstractHybridVaaclipseView) |
| superTypes += _typeReferenceBuilder.typeRef(BundleListener) |
| superTypes += _typeReferenceBuilder.typeRef(IUser.UserLocaleListener) |
| superTypes += _typeReferenceBuilder.typeRef(IEventDispatcher.Receiver) |
| superTypes += _typeReferenceBuilder.typeRef(DetachListener) |
| superTypes += _typeReferenceBuilder.typeRef(AttachListener) |
| superTypes += _typeReferenceBuilder.typeRef(IE4Focusable) |
| packageName = dataInterchangePackage.fullyQualifiedName.toString |
| it.fileHeader = dataInterchangePackage.documentation |
| it.toFields(dataInterchangePackage) |
| it.toConstructor(dataInterchangePackage) |
| it.toOperations(dataInterchangePackage) |
| ]) |
| |
| // create classes |
| for (dataInterchange : dataInterchangePackage.datInts) { |
| var clsName2 = dataInterchange.fullyQualifiedName |
| acceptor.accept(dataInterchange.toClass(clsName2), |
| [ |
| superTypes += _typeReferenceBuilder.typeRef(WorkerThreadRunnable) |
| annotations += _annotationTypesBuilder.annotationRef(SuppressWarnings, "serial") |
| it.fileHeader = dataInterchangePackage.documentation |
| it.toConstructor(dataInterchange) |
| it.toFields(dataInterchange) |
| it.toOperations(dataInterchange) |
| ]) |
| } |
| } |
| |
| |
| /** |
| * generate the fields in the inferred class. |
| * |
| * @param type |
| * the xtext generic types list |
| * @param pkg |
| * the current package inferred {@link DataInterchangePackage} |
| */ |
| def void toFields(JvmGenericType type, DataInterchangePackage pkg) { |
| var JvmField field = null |
| field = pkg.toField("sidebar", _typeReferenceBuilder.typeRef(VerticalLayout)) |
| type.members += field |
| field = pkg.toField("log", _typeReferenceBuilder.typeRef(Logger)) [setInitializer([ append('''LoggerFactory.getLogger(«pkg.fullyQualifiedName.lastSegment.toFirstUpper»TriggerView.class)''') ])] |
| field.final = true |
| field.static = true |
| type.members += field |
| field = pkg.toField("menu", _typeReferenceBuilder.typeRef(CssLayout)) |
| type.members += field |
| field = pkg.toField("branding", _typeReferenceBuilder.typeRef(CssLayout)) |
| type.members += field |
| field = pkg.toField("persistenceService", _typeReferenceBuilder.typeRef(IPersistenceService)) [ |
| annotations += _annotationTypesBuilder.annotationRef(Inject) |
| ] |
| type.members += field |
| field = pkg.toField("progressBars", _typeReferenceBuilder.typeRef(Map, _typeReferenceBuilder.typeRef(String), _typeReferenceBuilder.typeRef(WorkerThreadRunnable))) |
| type.members += field |
| field = pkg.toField("executorService", _typeReferenceBuilder.typeRef(ExecutorService)) |
| field.static = true |
| type.members += field |
| field = pkg.toField("dslMetadataService", _typeReferenceBuilder.typeRef(IDSLMetadataService)) [annotations += _annotationTypesBuilder.annotationRef(Inject)] |
| type.members += field |
| field = pkg.toField("dataInterchange", _typeReferenceBuilder.typeRef(IDataInterchange)) [annotations += _annotationTypesBuilder.annotationRef(Inject)] |
| type.members += field |
| field = pkg.toField("eventDispatcher", _typeReferenceBuilder.typeRef(IEventDispatcher))[annotations += _annotationTypesBuilder.annotationRef(Inject)] |
| type.members += field |
| field = pkg.toField("blobService", _typeReferenceBuilder.typeRef(IBlobService))[annotations += _annotationTypesBuilder.annotationRef(Inject)] |
| type.members += field |
| field = pkg.toField("user", _typeReferenceBuilder.typeRef(IUser))[annotations += _annotationTypesBuilder.annotationRef(Inject)] |
| type.members += field |
| field = pkg.toField("logo", _typeReferenceBuilder.typeRef(Label)) |
| type.members += field |
| field = pkg.toField("buttons", |
| _typeReferenceBuilder.typeRef(HashMap, _typeReferenceBuilder.typeRef(Button), _typeReferenceBuilder.typeRef(ArrayList, _typeReferenceBuilder.typeRef(String)))) |
| type.members += field |
| } |
| |
| /** |
| * <p>build the constructors to be used by an e4 application.</p> |
| * |
| */ |
| def void toConstructor(JvmDeclaredType type, DataInterchangePackage pkg) { |
| type.members += pkg.toConstructor([ |
| annotations += _annotationTypesBuilder.annotationRef(Inject) |
| parameters += pkg.toParameter("parent", _typeReferenceBuilder.typeRef(VerticalLayout)) |
| parameters += pkg.toParameter("context", _typeReferenceBuilder.typeRef(IEclipseContext)) |
| parameters += pkg.toParameter("app", _typeReferenceBuilder.typeRef(MApplication)) |
| body = [ append('''super(parent,context,app);''')] |
| ]) |
| } |
| |
| /** |
| * generate the fields in the inferred class. |
| * |
| * @param type |
| * the xtext generic types list |
| * @param pkg |
| * the current package inferred {@link DataInterchangePackage} |
| */ |
| def void toOperations(JvmGenericType type, DataInterchangePackage pkg) { |
| // create view |
| type.members += pkg.toMethod("createView", _typeReferenceBuilder.typeRef(Void::TYPE), [ |
| parameters += pkg.toParameter("parent", _typeReferenceBuilder.typeRef(VerticalLayout)) |
| body = [ append('''«pkg.createView»''')] |
| ]) |
| // create components |
| type.members += pkg.toMethod("createComponents", _typeReferenceBuilder.typeRef(Void::TYPE), [ |
| body = [ append('''«pkg.createComponents»''')] |
| ]) |
| // is duplicate |
| type.members += pkg.toMethod("isDuplicate", _typeReferenceBuilder.typeRef(boolean), [ |
| parameters += pkg.toParameter("name", _typeReferenceBuilder.typeRef(String)) |
| body = [ append('''«pkg.isDuplicate»''')] |
| ]) |
| // find layout |
| type.members += pkg.toMethod("findButtonLayout", _typeReferenceBuilder.typeRef(VerticalLayout), [ |
| parameters += pkg.toParameter("button", _typeReferenceBuilder.typeRef(Button)) |
| body = [ append('''«pkg.findButtonLayout»''')] |
| ]) |
| // remove progressbar |
| type.members += pkg.toMethod("removeProgressBar", _typeReferenceBuilder.typeRef(Void::TYPE), [ |
| parameters += pkg.toParameter("workerName", _typeReferenceBuilder.typeRef(String)) |
| body = [ append('''«pkg.removeProgressBar»''')] |
| ]) |
| // on bundle stopping - shutdown executorService |
| type.members += pkg.toMethod("bundleChanged", _typeReferenceBuilder.typeRef(Void::TYPE), [ |
| annotations += _annotationTypesBuilder.annotationRef(Override) |
| parameters += pkg.toParameter("event", _typeReferenceBuilder.typeRef(BundleEvent)) |
| body = [ append('''«pkg.bundleChanged»''')] |
| ]) |
| // attach |
| type.members += pkg.toMethod("attach", _typeReferenceBuilder.typeRef(Void::TYPE), |
| [ |
| parameters += pkg.toParameter("event", _typeReferenceBuilder.typeRef(AttachEvent)) |
| annotations += _annotationTypesBuilder.annotationRef(Override) |
| body = [append( |
| ''' |
| user.addUserLocaleListener(this); |
| eventDispatcher.addEventReceiver(this);''')] |
| |
| ]) |
| |
| // detach |
| type.members += pkg.toMethod("detach", _typeReferenceBuilder.typeRef(Void::TYPE), |
| [ |
| parameters += pkg.toParameter("event", _typeReferenceBuilder.typeRef(DetachEvent)) |
| annotations += _annotationTypesBuilder.annotationRef(Override) |
| body = [append( |
| ''' |
| user.removeUserLocaleListener(this); |
| eventDispatcher.removeEventReceiver(this);''')] |
| ]) |
| // focus |
| type.members += pkg.toMethod("setFocus", _typeReferenceBuilder.typeRef(Void::TYPE), [ |
| annotations += _annotationTypesBuilder.annotationRef(Focus) |
| body = [append( |
| ''' |
| Component parent = getParent(); |
| while(!(parent instanceof Panel) && parent != null) { |
| parent = parent.getParent(); |
| } |
| if(parent != null) { |
| ((Panel)parent).focus(); |
| }''')] |
| |
| ]) |
| // locale notification |
| type.members += pkg.toMethod("localeChanged", _typeReferenceBuilder.typeRef(Void::TYPE), |
| [ |
| visibility = JvmVisibility.PUBLIC |
| annotations += _annotationTypesBuilder.annotationRef(Override) |
| parameters += pkg.toParameter("locale", _typeReferenceBuilder.typeRef(Locale)) |
| body = [append('''«pkg.localeChanged»''')] |
| ]) |
| // event notification |
| type.members += pkg.toMethod("receiveEvent", _typeReferenceBuilder.typeRef(Void::TYPE), |
| [ |
| visibility = JvmVisibility.PUBLIC |
| annotations += _annotationTypesBuilder.annotationRef(Override) |
| parameters += pkg.toParameter("event", _typeReferenceBuilder.typeRef(EventDispatcherEvent)) |
| body = [append('''«pkg.receiveEvent»''')] |
| ]) |
| } |
| |
| /** |
| * let the app wait for finishing the workers before allowing to stop bundle. |
| * |
| * @param pkg |
| * the current package inferred {@link DataInterchangePackage} |
| * @return code fragment |
| */ |
| def String bundleChanged(DataInterchangePackage pkg) { |
| var body = "" |
| body = ''' |
| «body» |
| if (event.getType() == BundleEvent.STOPPING) { |
| log.debug("bundle is stopping"); |
| // This will make the executorService accept no new threads |
| // and finish all existing threads in the queue |
| if (executorService != null) { |
| executorService.shutdown(); |
| // Wait until all threads are finished |
| try { |
| executorService.awaitTermination(10, TimeUnit.SECONDS); |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| } |
| } |
| log.debug("all executors finished"); |
| } |
| ''' |
| return body |
| } |
| |
| /** |
| * find the right button layout for a given button. |
| * |
| * @param pkg |
| * the current package inferred {@link DataInterchangePackage} |
| * @return code fragment |
| */ |
| def String findButtonLayout(DataInterchangePackage pkg) { |
| var body = "" |
| body = ''' |
| «body» |
| int count = menu.getComponentCount(); |
| for(int i=0; i<count; i++) { |
| VerticalLayout buttonLayout = (VerticalLayout)menu.getComponent(i); |
| Button b = (Button)buttonLayout.getComponent(0); |
| if (b == button) { |
| return buttonLayout; |
| } |
| } |
| return null; |
| ''' |
| return body |
| } |
| |
| /** |
| * find out if a given thread-id is already running. |
| * |
| * @param pkg |
| * the current package inferred {@link DataInterchangePackage} |
| * @return code fragment |
| */ |
| def String isDuplicate(DataInterchangePackage pkg) { |
| var body = "" |
| body = ''' |
| «body» |
| boolean found = false; |
| for(String threadName : progressBars.keySet()) { |
| if (name.equals(threadName)) { |
| found = true; |
| break; |
| } |
| } |
| return found; |
| ''' |
| return body |
| } |
| |
| def String descriptionI18nKey(DataInterchange dataInterchange) { |
| if ((dataInterchange.descriptionValue == null) || dataInterchange.descriptionValue.isEmpty) { |
| dataInterchange.name |
| } |
| else { |
| dataInterchange.descriptionValue |
| } |
| } |
| |
| /** |
| * build an e4 compatible view and create necessary components. |
| * |
| * @param pkg |
| * the current package inferred {@link DataInterchangePackage} |
| * @return code fragment |
| */ |
| def String createView(DataInterchangePackage pkg) { |
| var body = ''' |
| getContext().set(IE4Focusable.class, this); |
| parent.addAttachListener(this); |
| parent.addDetachListener(this); |
| buttons = new HashMap<>(); |
| Bundle bundle = FrameworkUtil.getBundle(getClass()); |
| if (bundle != null) { |
| BundleContext ctx = bundle.getBundleContext(); |
| if (ctx != null) { |
| ctx.addBundleListener(this); |
| } |
| } |
| FrameworkUtil.getBundle(getClass()).getBundleContext().addBundleListener(this); |
| executorService = Executors.newFixedThreadPool(«NTHREADS»); |
| progressBars = new HashMap<String,WorkerThreadRunnable>(); |
| sidebar=new VerticalLayout(); |
| menu=new CssLayout(); |
| branding=new CssLayout(); |
| parent.setPrimaryStyleName("osbp"); |
| parent.setId("parent"); |
| parent.setSizeFull(); |
| sidebar.setSpacing(true); |
| sidebar.setId("sidebar"); |
| parent.addComponent(sidebar); |
| parent.setExpandRatio(sidebar, 1.0f); |
| // create sidebar |
| sidebar.addStyleName("osbpsidebar"); |
| sidebar.setSizeFull(); |
| sidebar.addComponent(branding); |
| // branding title |
| branding.addStyleName("branding"); |
| logo = new Label(); |
| logo.setContentMode(ContentMode.HTML); |
| logo.setSizeUndefined(); |
| branding.addComponent(logo); |
| // add menu |
| sidebar.addComponent(menu); |
| sidebar.setExpandRatio(menu, 1.0f); |
| |
| ''' |
| body = ''' |
| «body» |
| // add menu items |
| Button b; |
| VerticalLayout buttonLayout; |
| ''' |
| for (dataInterchange : pkg.datInts) { |
| body = ''' |
| «body» |
| b = new NativeButton(); |
| b.setHtmlContentAllowed(true); |
| buttons.put(b, new ArrayList<String>(Arrays.asList(new String[] {"«DataDSLModelGenerator.CAPTION__REPFIX_I18NKEY_IMPORT»", "«dataInterchange.name»","«dataInterchange.descriptionI18nKey»"}))); |
| b.addStyleName("icon-download"); |
| b.addClickListener(new ClickListener() { |
| @Override |
| public void buttonClick(ClickEvent event) { |
| log.debug("pressed «dataInterchange.name» import"); |
| «dataInterchange.getBasicRunConfiguration(false, dataInterchange.getFileURL, WorkerThreadRunnable.Direction.IMPORT.name)» |
| «dataInterchange.defaultVariableName».setName(UUID.randomUUID().toString()); |
| «dataInterchange.defaultVariableName».setEventDispatcher(eventDispatcher); |
| «dataInterchange.defaultVariableName».setUi(UI.getCurrent()); |
| «dataInterchange.defaultVariableName».setDirection(WorkerThreadRunnable.Direction.IMPORT); |
| findButtonLayout(event.getButton()).addComponent(«dataInterchange.defaultVariableName».getProgressBarArea()); |
| progressBars.put(«dataInterchange.defaultVariableName».getName(), «dataInterchange.defaultVariableName»); |
| executorService.execute(«dataInterchange.defaultVariableName»); |
| log.debug("«dataInterchange.name» import added to executor queue"); |
| } |
| }); |
| buttonLayout = new VerticalLayout(); |
| buttonLayout.addComponent(b); |
| menu.addComponent(buttonLayout); |
| ''' |
| body = ''' |
| «body» |
| b = new NativeButton(); |
| b.setHtmlContentAllowed(true); |
| buttons.put(b, new ArrayList<String>(Arrays.asList(new String[] {"«DataDSLModelGenerator.CAPTION__REPFIX_I18NKEY_EXPORT»", "«dataInterchange.name»","«dataInterchange.descriptionI18nKey»"}))); |
| b.addStyleName("icon-upload"); |
| b.addClickListener(new ClickListener() { |
| @Override |
| public void buttonClick(ClickEvent event) { |
| log.debug("pressed «dataInterchange.name» export"); |
| «dataInterchange.getBasicRunConfiguration(false, dataInterchange.getFileURL, WorkerThreadRunnable.Direction.EXPORT.name)» |
| «dataInterchange.defaultVariableName».setName(UUID.randomUUID().toString()); |
| «dataInterchange.defaultVariableName».setEventDispatcher(eventDispatcher); |
| «dataInterchange.defaultVariableName».setUi(UI.getCurrent()); |
| «dataInterchange.defaultVariableName».setDirection(WorkerThreadRunnable.Direction.EXPORT); |
| findButtonLayout(event.getButton()).addComponent(«dataInterchange.defaultVariableName».getProgressBarArea()); |
| progressBars.put(«dataInterchange.defaultVariableName».getName(), «dataInterchange.defaultVariableName»); |
| executorService.execute(«dataInterchange.defaultVariableName»); |
| log.debug("«dataInterchange.name» export added to executor queue"); |
| } |
| }); |
| buttonLayout = new VerticalLayout(); |
| buttonLayout.addComponent(b); |
| menu.addComponent(buttonLayout); |
| ''' |
| } |
| body = ''' |
| «body» |
| menu.addStyleName("menu"); |
| menu.setHeight("100%"); |
| ''' |
| return body |
| } |
| |
| def String getDefaultVariableName(DataInterchange dataInterchange) { |
| return dataInterchange.name.toFirstLower |
| } |
| |
| def String getBasicRunConfiguration(DataInterchange dataInterchange, boolean fqClass, String fileURL, String direction) { |
| var className = "" |
| if (fqClass) { |
| className = dataInterchange.fullyQualifiedName.toString |
| } |
| else { |
| className = dataInterchange.name |
| } |
| return |
| ''' |
| «className» «dataInterchange.getDefaultVariableName» = new «className»(); |
| String url = ProductConfiguration.getDatainterchangeConfiguration(); |
| if(url.isEmpty()) { |
| url = System.getProperty("user.home")+"/.osbee/"+"«(dataInterchange.eContainer as DataInterchangePackage).title»Config.xml"; |
| } |
| File file = new File(url); |
| if(file.exists()) { |
| FileInputStream fileInput; |
| try { |
| fileInput = new FileInputStream(file); |
| Properties properties = new Properties(); |
| properties.loadFromXML(fileInput); |
| fileInput.close(); |
| if(properties.getProperty("«dataInterchange.name»-«direction.toLowerCase()»") == null) { |
| «dataInterchange.getDefaultVariableName».setFileURL("«fileURL»"); |
| } else { |
| «dataInterchange.getDefaultVariableName».setFileURL(properties.getProperty("«dataInterchange.name»-«direction.toLowerCase()»")); |
| } |
| } catch (IOException e) { |
| StringWriter sw = new StringWriter(); |
| e.printStackTrace(new PrintWriter(sw)); |
| log.error("{}", sw.toString()); |
| return; |
| } |
| } else { |
| «dataInterchange.getDefaultVariableName».setFileURL("«fileURL»"); |
| } |
| «dataInterchange.getDefaultVariableName».setPersistenceService(persistenceService); |
| «dataInterchange.getDefaultVariableName».setDataInterchange(dataInterchange); |
| «dataInterchange.getDefaultVariableName».setEventDispatcher(eventDispatcher); |
| «dataInterchange.getDefaultVariableName».setBlobService(blobService); |
| ''' |
| } |
| |
| def String getFileURL(DataInterchange dataInterchange) { |
| switch(dataInterchange.fileEndpoint) { |
| DataInterchangeFileXML: return (dataInterchange.fileEndpoint as DataInterchangeFileXML).fileURL |
| DataInterchangeFileCSV: return (dataInterchange.fileEndpoint as DataInterchangeFileCSV).fileURL |
| DataInterchangeFileEDI: return (dataInterchange.fileEndpoint as DataInterchangeFileEDI).fileURL |
| } |
| return "" |
| } |
| |
| /** |
| * create more components. this fragment is repainted if something changes (e.g. language) |
| * |
| * @param pkg |
| * the current package inferred {@link DataInterchangePackage} |
| * @return code fragment |
| */ |
| def String createComponents(DataInterchangePackage pkg) { |
| return "" |
| } |
| |
| /** |
| * <p>build the constructor for each class.</p> |
| * |
| * @param pkg |
| * the current datainterchange inferred {@link DataInterchange} |
| */ |
| def void toConstructor(JvmDeclaredType type, DataInterchange dataInterchange) { |
| type.members += dataInterchange.toConstructor([ |
| body = [append(''' |
| setName("«dataInterchange.name»"); |
| ''')] |
| ]) |
| } |
| |
| /** |
| * <p>build the class variables.</p> |
| * |
| */ |
| def void toFields(JvmDeclaredType type, DataInterchange dataInterchange) { |
| var JvmField field = null |
| field = dataInterchange.toField("log", _typeReferenceBuilder.typeRef(Logger)) [setInitializer([ append('''LoggerFactory.getLogger("dataInterchange")''') ])] |
| field.final = true |
| field.static = true |
| type.members += field |
| field = dataInterchange.toField("dataInterchange", _typeReferenceBuilder.typeRef(IDataInterchange)) |
| type.members += field |
| field = dataInterchange.toField("em", _typeReferenceBuilder.typeRef(EntityManager)) |
| type.members += field |
| field = dataInterchange.toField("fileURL", _typeReferenceBuilder.typeRef(URL)) |
| type.members += field |
| field = dataInterchange.toField("file", _typeReferenceBuilder.typeRef(OutputStream)) |
| type.members += field |
| field = dataInterchange.toField("out", _typeReferenceBuilder.typeRef(OutputStream)) |
| type.members += field |
| field = dataInterchange.toField("transformerFactory", _typeReferenceBuilder.typeRef(TransformerFactory)) [setInitializer([ append('''TransformerFactory.newInstance()''') ])] |
| type.members += field |
| field = dataInterchange.toField("transformer", _typeReferenceBuilder.typeRef(Transformer)) |
| type.members += field |
| } |
| |
| /** |
| * <p>build the methods.</p> |
| * |
| */ |
| def void toOperations(JvmDeclaredType type, DataInterchange dataInterchange) { |
| type.members += dataInterchange.toGetter("dataInterchange", _typeReferenceBuilder.typeRef(IDataInterchange)) |
| type.members += dataInterchange.toSetter("dataInterchange", _typeReferenceBuilder.typeRef(IDataInterchange)) |
| type.members += dataInterchange.toMethod("run", _typeReferenceBuilder.typeRef(Void::TYPE), [ |
| annotations += _annotationTypesBuilder.annotationRef(Override) |
| body = [ append('''run(null);''')] |
| ]) |
| type.members += dataInterchange.toMethod("run", _typeReferenceBuilder.typeRef(Void::TYPE), [ |
| parameters += dataInterchange.toParameter("importListener", _typeReferenceBuilder.typeRef(IEntityImportInitializationListener)) |
| body = [ append('''«dataInterchange.performInterchange»''')] |
| ]) |
| type.members += dataInterchange.toMethod("init", _typeReferenceBuilder.typeRef(boolean), [ |
| visibility = JvmVisibility.PROTECTED |
| parameters += dataInterchange.toParameter("direction", _typeReferenceBuilder.typeRef(WorkerThreadRunnable.Direction)) |
| body = [ append('''«dataInterchange.init»''')] |
| ]) |
| type.members += dataInterchange.toMethod("setFileURL", _typeReferenceBuilder.typeRef(Void::TYPE), [ |
| parameters += dataInterchange.toParameter("filePath", _typeReferenceBuilder.typeRef(String)) |
| body = [ append('''«dataInterchange.fileUrl»''')] |
| ]) |
| } |
| |
| /** |
| * <p>create URL from filepath or other string.</p> |
| * |
| * @param pkg |
| * the current datainterchange inferred {@link DataInterchange} |
| * @return code fragment |
| */ |
| def fileUrl(DataInterchange dataInterchange) |
| ''' |
| fileURL = null; |
| String path = filePath; |
| if (filePath.startsWith("file://") && org.eclipse.osbp.utils.common.SystemInformation.isWindowsOS()) { |
| path = filePath.substring("file://".length()); |
| } |
| try { |
| fileURL = new URL(path); |
| } catch (MalformedURLException e1) { |
| if(e1.getMessage().startsWith("unknown protocol") || e1.getMessage().startsWith("no protocol")) { |
| try { |
| fileURL = Paths.get(path).toUri().toURL(); |
| } catch (MalformedURLException e2) { |
| StringWriter sw = new StringWriter(); |
| e2.printStackTrace(new PrintWriter(sw)); |
| log.error("{}", sw.toString()); |
| } |
| } |
| } |
| ''' |
| |
| /** |
| * init factory to create the core import process. |
| * setup listeners for UI communication. |
| * setup persistence layer. |
| * |
| * @param pkg |
| * the current datainterchange inferred {@link DataInterchange} |
| * @return code fragment |
| */ |
| def String init(DataInterchange dataInterchange) { |
| var firstEntity = (dataInterchange.path.iterator.next as DataInterchangeBean) |
| var body = |
| ''' |
| try { |
| transformerFactory.setAttribute("indent-number", 4); |
| transformer = transformerFactory.newTransformer(); |
| transformer.setOutputProperty(OutputKeys.INDENT, "yes"); |
| transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); |
| transformer.setOutputProperty(OutputKeys.STANDALONE, "yes"); |
| transformer.setOutputProperty(OutputKeys.MEDIA_TYPE, "text/xml"); |
| |
| // init |
| setProgressBarEnabled(true); |
| setProgressIndeterminated(true); |
| if (log.isDebugEnabled()) log.debug("initializing datainterchange factory"); |
| // get entity manager |
| if (log.isDebugEnabled()) log.debug("opening entity manager to persist results"); |
| getPersistenceService().registerPersistenceUnit("«firstEntity.entity.persistenceUnit»", «firstEntity.entity.fullyQualifiedName».class); |
| em = getPersistenceService().getEntityManagerFactory("«firstEntity.entity.persistenceUnit»").createEntityManager(); |
| if(dataInterchange != null) { |
| dataInterchange.open(FrameworkUtil.getBundle(getClass()),"«DSLOutputConfigurationProvider.SMOOKS_OUTPUT_DIRECTORY»/«dataInterchange.name»-"+direction.toString().toLowerCase()+".xml"); |
| dataInterchange.setEventListener(this); |
| dataInterchange.setEntityManager(em); |
| } |
| «IF dataInterchange.createReport» |
| if (log.isDebugEnabled()) log.debug("reporting is on - impacting performance"); |
| if(dataInterchange != null) { |
| String location = FrameworkUtil.getBundle(this.getClass()).getLocation()+"«DSLOutputConfigurationProvider.SMOOKS_OUTPUT_DIRECTORY»/«dataInterchange.name»-"+direction.toString().toLowerCase()+"-report.html"; |
| location = location.replace("reference:file:/", ""); |
| dataInterchange.enableReport(location); |
| } |
| «ENDIF» |
| } catch (TransformerConfigurationException | SAXException | IOException e) { |
| StringWriter sw = new StringWriter(); |
| e.printStackTrace(new PrintWriter(sw)); |
| log.error("{}", sw.toString()); |
| return false; |
| } |
| if(direction == Direction.EXPORT) { |
| int openTry = 0; |
| file = null; |
| URI uri = null; |
| try { |
| uri = fileURL.toURI(); |
| } catch (URISyntaxException e) { |
| StringWriter sw = new StringWriter(); |
| e.printStackTrace(new PrintWriter(sw)); |
| log.error("{}", sw.toString()); |
| return false; |
| } |
| do { |
| Path path = null; |
| path = Paths.get(uri); |
| try { |
| // find a unique name - similar to given |
| file = Files.newOutputStream(path, StandardOpenOption.CREATE_NEW); |
| } catch (FileAlreadyExistsException ae) { |
| openTry ++; |
| try { |
| uri = fileURL.toURI(); |
| int pos = uri.getPath().lastIndexOf('.'); |
| if(pos == -1) { |
| uri = new URI(uri.getScheme()+":"+uri.getPath()+openTry); |
| } else { |
| uri = new URI(uri.getScheme()+":"+uri.getPath().substring(0,pos)+openTry+"."+uri.getPath().substring(pos+1)); |
| } |
| } catch (URISyntaxException e) { |
| StringWriter sw = new StringWriter(); |
| e.printStackTrace(new PrintWriter(sw)); |
| log.error("{}", sw.toString()); |
| return false; |
| } |
| } catch (IOException e) { |
| StringWriter sw = new StringWriter(); |
| e.printStackTrace(new PrintWriter(sw)); |
| log.error("{}", sw.toString()); |
| return false; |
| } |
| }while(file == null); |
| out = new BufferedOutputStream(file); |
| } |
| return true; |
| ''' |
| return body |
| } |
| |
| /** |
| * use factory to create the core import process. |
| * setup listeners for UI communication. |
| * setup persistence layer. |
| * |
| * @param pkg |
| * the current datainterchange inferred {@link DataInterchange} |
| * @return code fragment |
| */ |
| def String performInterchange(DataInterchange dataInterchange) { |
| var firstEntityBean = (dataInterchange.path.iterator.next as DataInterchangeBean) |
| firstEntityBean.hasBlobMapping = firstEntityBean.mappings.filter(DataInterchangeBlobMapping).size > 0 |
| var body = ''' |
| if(!init(getDirection())) { |
| return; |
| } |
| if(dataInterchange == null) { |
| log.error("dataInterchange is not present - download from www.osbee.org"); |
| return; |
| } |
| try { |
| if(getDirection()==WorkerThreadRunnable.Direction.IMPORT) { |
| ''' |
| body = ''' |
| «body» |
| if (importListener != null) { |
| importListener.notifyInitializationStep("datainterchange «dataInterchange.name.toFirstUpper» load.", 0.4, 0.45, 0, 0); |
| } |
| ''' |
| |
| for (path:dataInterchange.path) { |
| for (lookup:path.lookup) { |
| if (lookup.cached) { |
| body = ''' |
| «body» |
| em.setProperty(PersistenceUnitProperties.CACHE_SIZE_+"«lookup.entity.fullyQualifiedName»", "«lookup.cacheSize»"); |
| ''' |
| } |
| } |
| } |
| |
| // import beans as list if no mark latest, other wise as a single bean |
| body = ''' |
| «body» |
| Object result = null; |
| if (log.isDebugEnabled()) log.debug("filtering starts"); |
| setProgressIndeterminated(false); |
| InputStream contents = dataInterchange.openStream(fileURL); |
| setLength(contents.available()); |
| setAvgElementSize(«IF dataInterchange.elementSize==0»10«ELSE»«dataInterchange.elementSize»«ENDIF»); |
| result = dataInterchange.importSource(contents, "«firstEntityBean.entity.name»«IF !firstEntityBean.markLatest»List«ENDIF»"«IF dataInterchange.fileEndpoint.encoding !== null», "«dataInterchange.fileEndpoint.encoding»"«ENDIF»); |
| if (log.isDebugEnabled()) log.debug("filtering finished"); |
| ''' |
| |
| if (!firstEntityBean.markLatest) { |
| body = ''' |
| «body» |
| if(result != null) { |
| List<«firstEntityBean.entity.fullyQualifiedName»> «firstEntityBean.entity.name.toFirstLower»List = Arrays.asList((«firstEntityBean.entity.fullyQualifiedName»[]) result); |
| em.getTransaction().begin(); |
| if (log.isDebugEnabled()) log.debug("persisting results"); |
| int total = «firstEntityBean.entity.name.toFirstLower»List.size(); |
| int count = 0; |
| long lastStep = System.currentTimeMillis(); |
| if (importListener != null) { |
| importListener.notifyInitializationStep("datainterchange «dataInterchange.name.toFirstUpper»", 0.4, 0.5, count, total); |
| } |
| for(«firstEntityBean.entity.fullyQualifiedName» «firstEntityBean.entity.name.toFirstLower»:«firstEntityBean.entity.name.toFirstLower»List) { |
| ''' |
| if(firstEntityBean.hasBlobMapping && dataInterchange.mode!=EntityManagerMode.REMOVE){ |
| for(mapping:firstEntityBean.mappings){ |
| if(mapping instanceof DataInterchangeBlobMapping){ |
| var m = (mapping as DataInterchangeBlobMapping) |
| var blobFileName = '''«firstEntityBean.entity.name.toFirstLower».get«m.property.name.toFirstUpper»()«IF m.blobFileExtension != null» + ".«m.blobFileExtension»"«ENDIF»''' |
| body = ''' |
| «body» |
| try (InputStream inputStream = new BufferedInputStream( |
| «IF m.blobPath == null» |
| this.getClass().getClassLoader().getResourceAsStream("/«firstEntityBean.entity.name»/" + «blobFileName») |
| «ELSE» |
| new FileInputStream("«m.blobPath»/" + «blobFileName»)«ENDIF»)) { |
| String «firstEntityBean.entity.name.toFirstLower»_«m.property.name»Id = getBlobService().createBlobMapping( |
| inputStream, |
| «firstEntityBean.entity.name.toFirstLower».get«m.property.name.toFirstUpper»(), |
| "«m.mimeType»" |
| ); |
| «firstEntityBean.entity.name.toFirstLower».set«m.property.name.toFirstUpper»(«firstEntityBean.entity.name.toFirstLower»_«m.property.name»Id); |
| } catch (IOException e) { |
| log.error(e.getLocalizedMessage()); |
| } |
| ''' |
| } |
| } |
| } |
| body = |
| ''' |
| «body» |
| try { |
| «IF dataInterchange.mode==EntityManagerMode.PERSIST»em.persist(«firstEntityBean.entity.name.toFirstLower»); |
| «ELSEIF dataInterchange.mode==EntityManagerMode.MERGE»em.merge(«firstEntityBean.entity.name.toFirstLower»); |
| «ELSEIF dataInterchange.mode==EntityManagerMode.REMOVE»«firstEntityBean.entity.fullyQualifiedName» toBeRemoved = em.merge(«firstEntityBean.entity.name.toFirstLower»); |
| em.remove(toBeRemoved);«ENDIF» |
| } |
| catch (ConstraintViolationException cve) { |
| log.error("«firstEntityBean.entity.name.toFirstLower» #"+(count+1)+"/"+total+": "+cve.getLocalizedMessage()); |
| for (ConstraintViolation<?> violation : cve.getConstraintViolations()) { |
| Object value = violation.getInvalidValue(); |
| if (value == null) { |
| value = "<null>"; |
| } |
| log.error("- property:" |
| +violation.getLeafBean().toString()+"."+violation.getPropertyPath().toString() |
| +" value:'"+value.toString() |
| +" violation:"+violation.getMessage()); |
| } |
| } |
| count++; |
| long thisStep = System.currentTimeMillis(); |
| if ((importListener != null) && ((count % importListener.getInitializationSubStepNotifySize() == 0) || (thisStep-lastStep > 2500))) { |
| lastStep = System.currentTimeMillis(); |
| importListener.notifyInitializationStep("datainterchange «dataInterchange.name.toFirstUpper»", 0.4, 0.5, count, total); |
| } |
| } |
| if (importListener != null) { |
| importListener.notifyInitializationStep("datainterchange «dataInterchange.name.toFirstUpper»", 0.4, 0.5, count, total); |
| } |
| if (log.isDebugEnabled()) log.debug("committing results"); |
| |
| em.getTransaction().commit(); |
| ''' |
| } else { |
| body = ''' |
| «body» |
| if(result != null) { |
| «firstEntityBean.entity.fullyQualifiedName» «firstEntityBean.entity.name.toFirstLower» = («firstEntityBean.entity.fullyQualifiedName») result; |
| ''' |
| if(firstEntityBean.hasBlobMapping && dataInterchange.mode!=EntityManagerMode.REMOVE){ |
| for(mapping:firstEntityBean.mappings){ |
| if(mapping instanceof DataInterchangeBlobMapping){ |
| var m = (mapping as DataInterchangeBlobMapping) |
| var blobFileName = '''«firstEntityBean.entity.name.toFirstLower».get«m.property.name.toFirstUpper»()«IF m.blobFileExtension != null» + "." + "«m.blobFileExtension»"«ENDIF»''' |
| body = ''' |
| «body» |
| try (InputStream inputStream = new BufferedInputStream( |
| «IF m.blobPath == null» |
| this.getClass().getClassLoader().getResourceAsStream("/«firstEntityBean.entity.name»/" + «blobFileName») |
| «ELSE» |
| new FileInputStream("«m.blobPath»/" + «blobFileName»)«ENDIF»)) { |
| String «m.property.name.toFirstLower»Id = blobUpload.createBlobMapping( |
| inputStream, |
| «firstEntityBean.entity.name.toFirstLower».get«m.property.name.toFirstUpper»(), |
| "«m.mimeType»", |
| blobAPI |
| ); |
| «firstEntityBean.entity.name.toFirstLower».set«m.property.name.toFirstUpper»(«m.property.name.toFirstLower»Id); |
| } catch (IOException e) { |
| log.error(e.getLocalizedMessage()); |
| } |
| ''' |
| } |
| } |
| } |
| body = ''' |
| «body» |
| em.getTransaction().begin(); |
| if (log.isDebugEnabled()) log.debug("storing results"); |
| «IF dataInterchange.mode==EntityManagerMode.PERSIST»em.persist(«firstEntityBean.entity.name.toFirstLower»); |
| «ELSEIF dataInterchange.mode==EntityManagerMode.MERGE»em.merge(«firstEntityBean.entity.name.toFirstLower»); |
| «ELSEIF dataInterchange.mode==EntityManagerMode.REMOVE»«firstEntityBean.entity.fullyQualifiedName» toBeRemoved = em.merge(«firstEntityBean.entity.name.toFirstLower»); |
| em.remove(toBeRemoved);«ENDIF» |
| if (log.isDebugEnabled()) log.debug("committing results"); |
| em.getTransaction().commit(); |
| ''' |
| } |
| if (firstEntityBean.markLatest) { |
| body = ''' |
| «body» |
| if (log.isDebugEnabled()) log.debug("mark results as latest import"); |
| em.setProperty(QueryHints.PESSIMISTIC_LOCK, PessimisticLock.Lock); |
| em.getTransaction().begin(); |
| em.createQuery("update «firstEntityBean.entity.name» set «firstEntityBean.latestProperty.name» = 0").executeUpdate(); |
| em.createQuery("update «firstEntityBean.entity.name» set «firstEntityBean.latestProperty.name» = 1 where «»id= :id").setParameter("id", «firstEntityBean.entity.name.toFirstLower».getId()).executeUpdate(); |
| if (log.isDebugEnabled()) log.debug("committing mark"); |
| em.getTransaction().commit(); |
| ''' |
| } |
| for (path:dataInterchange.path) { |
| var entity = path.entity |
| body = ''' |
| «body» |
| if(getEventDispatcher() != null) { |
| EventDispatcherEvent «entity.name.toLowerCase»Event = new EventDispatcherEvent(EventDispatcherCommand.REFRESH, "«entity.fullyQualifiedName»", "«dataInterchange.fullyQualifiedName»"); |
| getEventDispatcher().sendEvent(«entity.name.toLowerCase»Event); |
| } |
| ''' |
| } |
| body = ''' |
| «body» |
| if (log.isDebugEnabled()) log.debug("results persisted"); |
| } else { |
| if (log.isDebugEnabled()) log.debug("no results found"); |
| } |
| ''' |
| var root = dataInterchange.path.findFirst[it|!it.markLatest] |
| if(root !== null) { |
| body = ''' |
| «body» |
| } else { |
| if (log.isDebugEnabled()) log.debug("prepare export"); |
| CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); |
| |
| if (log.isDebugEnabled()) log.debug("evaluate root entity count"); |
| CriteriaQuery<Long> countQuery = criteriaBuilder.createQuery(Long.class); |
| countQuery.select(criteriaBuilder.count(countQuery.from(«root.entity.fullyQualifiedName».class))); |
| Long count = em.createQuery(countQuery).getSingleResult(); |
| if (log.isDebugEnabled()) log.debug("root entity count is "+count.toString()); |
| setLength(count*«IF dataInterchange.elementSize==0»10«ELSE»«dataInterchange.elementSize»«ENDIF»); |
| setAvgElementSize(1); |
| |
| CriteriaQuery<«root.entity.fullyQualifiedName»> criteriaQuery = criteriaBuilder.createQuery(«root.entity.fullyQualifiedName».class); |
| Root<«root.entity.fullyQualifiedName»> from = criteriaQuery.from(«root.entity.fullyQualifiedName».class); |
| CriteriaQuery<«root.entity.fullyQualifiedName»> select = criteriaQuery.multiselect(from); |
| |
| TypedQuery<«root.entity.fullyQualifiedName»> typedQuery = em.createQuery(select); |
| setProgressIndeterminated(false); |
| List<«root.entity.fullyQualifiedName»> allResults = typedQuery.getResultList(); |
| StringWriter writer = new StringWriter(); |
| if(dataInterchange != null) { |
| dataInterchange.exportSource(allResults, writer); |
| } |
| out.write(writer.toString().getBytes()); |
| if (log.isDebugEnabled()) log.debug("export finished"); |
| } |
| ''' |
| } else { |
| body = ''' |
| «body» |
| }''' |
| } |
| body = ''' |
| «body» |
| } catch (DataInterchangeException | IOException e) { |
| StringWriter sw = new StringWriter(); |
| e.printStackTrace(new PrintWriter(sw)); |
| log.error("«dataInterchange.name»:{}", sw.toString()); |
| } finally { |
| if(file != null) { |
| try { |
| out.close(); |
| file.close(); |
| } catch (IOException e) { |
| StringWriter sw = new StringWriter(); |
| e.printStackTrace(new PrintWriter(sw)); |
| log.error("«dataInterchange.name»:{}", sw.toString()); |
| } |
| } |
| if(dataInterchange != null) { |
| dataInterchange.close(); |
| } |
| if (em != null) { |
| em.close(); |
| } |
| // remove progress bar |
| if(getEventDispatcher() != null) { |
| EventDispatcherEvent evnt = new EventDispatcherEvent(EventDispatcherCommand.REMOVE_PROGRESSBAR, getName(), "DataInterchangeWorkerThread"); |
| getEventDispatcher().sendEvent(evnt); |
| } |
| if (log.isDebugEnabled()) log.debug("datainterchange finished"); |
| } |
| ''' |
| return body |
| } |
| |
| /** |
| * handle the worker progress bar. provide the appropriate code. |
| * |
| * @param pkg |
| * the current package inferred {@link DataInterchangePackage} |
| * @return code fragment |
| */ |
| def String removeProgressBar(DataInterchangePackage pkg) { |
| var body = "" |
| body = ''' |
| «body» |
| // a worker notified this view that it is finished |
| if (progressBars.containsKey(workerName)) { |
| final WorkerThreadRunnable worker = progressBars.get(workerName); |
| ((VerticalLayout)worker.getProgressBarArea().getParent()).removeComponent(worker.getProgressBarArea()); |
| progressBars.remove(workerName); |
| } |
| ''' |
| return body |
| } |
| |
| def localeChanged(DataInterchangePackage pkg) |
| ''' |
| «IF pkg.title != null» |
| if(logo != null) { |
| logo.setValue(dslMetadataService.translate(locale.toLanguageTag(), "«pkg.title»")); |
| } |
| «ENDIF» |
| if(buttons != null) { |
| for(Button button: buttons.keySet()) { |
| ArrayList i18nKeys = buttons.get(button); |
| button.setCaption(dslMetadataService.translate(locale.toLanguageTag(),(String)i18nKeys.get(1))); |
| button.setDescription(dslMetadataService.translate(locale.toLanguageTag(),(String)i18nKeys.get(0))+" "+dslMetadataService.translate(locale.toLanguageTag(),(String)i18nKeys.get(2))); |
| } |
| }''' |
| |
| def String receiveEvent(DataInterchangePackage pkg) { |
| var body = "" |
| body = ''' |
| «body» |
| switch(event.getCommand()) { |
| case REMOVE_PROGRESSBAR: |
| removeProgressBar(event.getTopic()); |
| break; |
| } |
| ''' |
| return body |
| } |
| |
| } |