| /** |
| * |
| * 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.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.Iterator |
| import java.util.Locale |
| import java.util.Map |
| import java.util.concurrent.ExecutorService |
| import javax.annotation.PostConstruct |
| import javax.annotation.PreDestroy |
| 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.core.services.events.IEventBroker |
| import org.eclipse.e4.ui.model.application.MApplication |
| import org.eclipse.osbp.dsl.entity.xtext.extensions.ModelExtensions |
| import org.eclipse.osbp.dsl.semantic.common.types.LReference |
| import org.eclipse.osbp.dsl.semantic.entity.LEntity |
| import org.eclipse.osbp.osgi.hybrid.api.AbstractHybridVaaclipseView |
| import org.eclipse.osbp.persistence.IPersistenceService |
| import org.eclipse.osbp.ui.api.metadata.IDSLMetadataService |
| import org.eclipse.osbp.ui.api.user.IUser |
| import org.eclipse.osbp.utils.constants.GeneratorConstants |
| import org.eclipse.osbp.utils.entitymock.IEntityImportInitializationListener |
| import org.eclipse.osbp.xtext.datainterchange.DataInterchange |
| import org.eclipse.osbp.xtext.datainterchange.DataInterchangeBean |
| 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.common.WorkerThreadRunnable |
| 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.milyn.Smooks |
| import org.milyn.SmooksFactory |
| import org.milyn.container.ExecutionContext |
| import org.osgi.framework.BundleEvent |
| import org.osgi.framework.BundleListener |
| import org.osgi.service.event.EventHandler |
| import org.slf4j.Logger |
| |
| /** |
| * <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. Underlying components |
| * are from the smooks repository |
| * </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) |
| documentation = GeneratorConstants.GENERATED_CLASSES_DOCUMENTATION |
| annotations += _annotationTypesBuilder.annotationRef(SuppressWarnings, "serial") |
| packageName = dataInterchangePackage.fullyQualifiedName.toString |
| it.toFields(dataInterchangePackage) |
| it.toConstructor(dataInterchangePackage) |
| it.toOperations(dataInterchangePackage) |
| ]) |
| |
| // create smooks classes |
| for (dataInterchange : dataInterchangePackage.datInts) { |
| var clsName2 = dataInterchange.fullyQualifiedName |
| acceptor.accept(dataInterchange.toClass(clsName2), |
| [ |
| superTypes += _typeReferenceBuilder.typeRef(WorkerThreadRunnable) |
| annotations += _annotationTypesBuilder.annotationRef(SuppressWarnings, "serial") |
| documentation = GeneratorConstants.GENERATED_CLASSES_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 |
| var name = pkg.name.toString.replace(".",":") |
| var String[] parts = name.split(":") |
| val String clsName = parts.get(parts.size-1).toFirstUpper |
| field = pkg.toField("log", _typeReferenceBuilder.typeRef(Logger)) [setInitializer([ append('''LoggerFactory.getLogger(«clsName»TriggerView.class)''') ])] |
| field.final = true |
| field.static = true |
| type.members += field |
| field = pkg.toField("menu", _typeReferenceBuilder.typeRef(CssLayout)) |
| type.members += field |
| field = pkg.toField("workerInfo", _typeReferenceBuilder.typeRef(EventHandler)) |
| type.members += field |
| field = pkg.toField("branding", _typeReferenceBuilder.typeRef(CssLayout)) |
| type.members += field |
| field = pkg.toField("eventBroker", _typeReferenceBuilder.typeRef(IEventBroker)) [ |
| annotations += _annotationTypesBuilder.annotationRef(Inject) |
| ] |
| 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("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))) |
| 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»''')] |
| ]) |
| // unique name |
| type.members += pkg.toMethod("uniqueName", _typeReferenceBuilder.typeRef(String), [ |
| parameters += pkg.toParameter("name", _typeReferenceBuilder.typeRef(String)) |
| body = [ append('''«pkg.uniqueName»''')] |
| ]) |
| // 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»''')] |
| ]) |
| // 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»''')] |
| ]) |
| // subscribe to eventBroker |
| type.members += pkg.toMethod("subscribe", _typeReferenceBuilder.typeRef(Void::TYPE), [ |
| visibility = JvmVisibility.PROTECTED |
| annotations += _annotationTypesBuilder.annotationRef(PostConstruct) |
| body = [append('''«pkg.subscribe»''')] |
| ]) |
| // unsubscribe from eventBroker |
| type.members += pkg.toMethod("unsubscribe", _typeReferenceBuilder.typeRef(Void::TYPE), [ |
| visibility = JvmVisibility.PROTECTED |
| annotations += _annotationTypesBuilder.annotationRef(PreDestroy) |
| body = [append('''«pkg.unsubscribe»''')] |
| ]) |
| // 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»''')] |
| ]) |
| } |
| |
| /** |
| * handle the worker progress UI. provide the appropriate code. |
| * |
| * @param pkg |
| * the current package inferred {@link DataInterchangePackage} |
| * @return code fragment |
| */ |
| def String workerInfo(DataInterchangePackage pkg) { |
| var body = "" |
| body = ''' |
| «body» |
| new EventHandler() { |
| @Override |
| public void handleEvent(Event event) { |
| // a worker notified this view that it is finished |
| String workername = (String)event.getProperty(EventUtils.DATA); |
| if (progressBars.containsKey(workername)) { |
| final WorkerThreadRunnable worker = progressBars.get(workername); |
| ((VerticalLayout)worker.getProgressBarArea().getParent()).removeComponent(worker.getProgressBarArea()); |
| progressBars.remove(workername); |
| } |
| } |
| }; |
| ''' |
| return body |
| } |
| |
| /** |
| * subscribe the event broker for messages on changed locale and worker progress. |
| * |
| * @param pkg |
| * the current package inferred {@link DataInterchangePackage} |
| * @return code fragment |
| */ |
| def String subscribe(DataInterchangePackage pkg) { |
| var body = "" |
| body = ''' |
| «body» |
| eventBroker.subscribe(EventBrokerMsg.WORKER_THREAD_INFO, workerInfo); |
| ''' |
| return body |
| } |
| |
| /** |
| * unsubscribe from event broker for messages. |
| * |
| * @param pkg |
| * the current package inferred {@link DataInterchangePackage} |
| * @return code fragment |
| */ |
| def String unsubscribe(DataInterchangePackage pkg) { |
| var body = "" |
| body = ''' |
| «body» |
| eventBroker.unsubscribe(workerInfo); |
| ''' |
| return body |
| } |
| |
| /** |
| * normalize package name. |
| * |
| * @param pkg |
| * the current package inferred {@link DataInterchangePackage} |
| * @return normalized package name |
| */ |
| def String toEventID(DataInterchangePackage pkg) { |
| return pkg.fullyQualifiedName.toString.toUpperCase.replaceAll("(\\W)","_") |
| } |
| |
| /** |
| * 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 |
| } |
| |
| /** |
| * make a name unique by concatenating a number. |
| * |
| * @param pkg |
| * the current package inferred {@link DataInterchangePackage} |
| * @return code fragment |
| */ |
| def String uniqueName(DataInterchangePackage pkg) { |
| var body = "" |
| body = ''' |
| «body» |
| Integer cnt = 0; |
| String searchName; |
| do { |
| if (cnt > 0) { |
| searchName = name+cnt.toString(); |
| } else { |
| searchName = name; |
| } |
| cnt ++; |
| }while(isDuplicate(searchName)); |
| return searchName; |
| ''' |
| 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 = ''' |
| buttons = new HashMap<Button, ArrayList>(); |
| workerInfo = «pkg.workerInfo» |
| 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"); |
| String uniqueName = uniqueName("«dataInterchange.name»"); |
| «dataInterchange.getBasicRunConfiguration(false, dataInterchange.getFileURL)» |
| «dataInterchange.defaultVariableName».setName(uniqueName); |
| «dataInterchange.defaultVariableName».setEventBroker(eventBroker); |
| «dataInterchange.defaultVariableName».setUi(UI.getCurrent()); |
| «dataInterchange.defaultVariableName».setDirection(WorkerThreadRunnable.Direction.IMPORT); |
| «IF dataInterchange.progressBarStyle!=null»«dataInterchange.defaultVariableName».setProgressBarStyleName("«dataInterchange.progressBarStyle.literal»");«ENDIF» |
| findButtonLayout(event.getButton()).addComponent(«dataInterchange.defaultVariableName».getProgressBarArea()); |
| progressBars.put(uniqueName, «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"); |
| String uniqueName = uniqueName("«dataInterchange.name»"); |
| «dataInterchange.getBasicRunConfiguration(false, dataInterchange.getFileURL)» |
| «dataInterchange.defaultVariableName».setName(uniqueName); |
| «dataInterchange.defaultVariableName».setEventBroker(eventBroker); |
| «dataInterchange.defaultVariableName».setUi(UI.getCurrent()); |
| «dataInterchange.defaultVariableName».setDirection(WorkerThreadRunnable.Direction.EXPORT); |
| «IF dataInterchange.progressBarStyle!=null»«dataInterchange.defaultVariableName».setProgressBarStyleName("«dataInterchange.progressBarStyle.literal»");«ENDIF» |
| findButtonLayout(event.getButton()).addComponent(«dataInterchange.defaultVariableName».getProgressBarArea()); |
| progressBars.put(uniqueName, «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%"); |
| user.addUserLocaleListener(this); |
| ''' |
| return body |
| } |
| |
| def String getDefaultVariableName(DataInterchange dataInterchange) { |
| return dataInterchange.name.toFirstLower |
| } |
| |
| def String getBasicRunConfiguration(DataInterchange dataInterchange, boolean fqClass, String fileURL) { |
| var className = "" |
| if (fqClass) { |
| className = dataInterchange.fullyQualifiedName.toString |
| } |
| else { |
| className = dataInterchange.name |
| } |
| return ''' |
| «className» «dataInterchange.getDefaultVariableName» = new «className»(); |
| «dataInterchange.getDefaultVariableName».setFileURL("«fileURL»"); |
| «dataInterchange.getDefaultVariableName».setPersistenceService(persistenceService); |
| ''' |
| } |
| |
| 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 smooks 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("smooksOSGIFactory", _typeReferenceBuilder.typeRef(SmooksFactory)) [setInitializer([ append('''null''') ])] |
| type.members += field |
| field = dataInterchange.toField("smooks", _typeReferenceBuilder.typeRef(Smooks)) |
| type.members += field |
| // field = dataInterchange.toField("xmlBinding", _typeReferenceBuilder.typeRef(XMLBinding)) |
| // 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("executionContext", _typeReferenceBuilder.typeRef(ExecutionContext)) |
| 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("pollingInterval", _typeReferenceBuilder.typeRef(int)) [setInitializer([ append('''500''') ])] |
| 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.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.performSmooks»''')] |
| ]) |
| 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.isMacOS()) { |
| path = filePath.substring("file://".length()); |
| } |
| try { |
| fileURL = new URL(path); |
| } catch (MalformedURLException e1) { |
| if(e1.getMessage().startsWith("unknown protocol")) { |
| try { |
| fileURL = Paths.get(path).toUri().toURL(); |
| } catch (MalformedURLException e2) { |
| log.error(e2.getLocalizedMessage()+e2.getCause()); |
| } |
| } |
| } |
| ''' |
| |
| /** |
| * init smooks 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 = |
| ''' |
| if(getEventBroker()!=null) { |
| pollingInterval = UI.getCurrent().getPollInterval(); |
| UI.getCurrent().setPollInterval(500); |
| } |
| 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 smooks |
| setProgressBarEnabled(true); |
| setProgressIndeterminated(true); |
| if (log.isDebugEnabled()) log.debug("initializing smooks factory"); |
| smooksOSGIFactory = new SmooksOSGIFactory(FrameworkUtil.getBundle(this.getClass())); |
| smooks = smooksOSGIFactory.createInstance(FrameworkUtil.getBundle(this.getClass()).getResource("«DSLOutputConfigurationProvider.SMOOKS_OUTPUT_DIRECTORY»/«dataInterchange.name»-"+direction.toString().toLowerCase()+".xml").openStream()); |
| // prepare execution context |
| executionContext = smooks.createExecutionContext(); |
| executionContext.setEventListener(this); |
| // get entity manager |
| if (log.isDebugEnabled()) log.debug("opening entity manager to persist smooks results"); |
| getPersistenceService().registerPersistenceUnit("«firstEntity.entity.persistenceUnit»", «firstEntity.entity.fullyQualifiedName».class); |
| em = getPersistenceService().getEntityManagerFactory("«firstEntity.entity.persistenceUnit»").createEntityManager(); |
| «IF dataInterchange.createReport» |
| // create a filtering report -- impacts performance |
| if (log.isDebugEnabled()) log.debug("reporting is on - impacting performance"); |
| String location = FrameworkUtil.getBundle(this.getClass()).getLocation()+"«DSLOutputConfigurationProvider.SMOOKS_OUTPUT_DIRECTORY»/«dataInterchange.name»-"+direction.toString().toLowerCase()+"-report.html"; |
| executionContext.setEventListener(new HtmlReportGenerator(location)); |
| «ENDIF» |
| } catch (Exception e) { |
| if(getEventBroker()!=null) { |
| UI.getCurrent().setPollInterval(pollingInterval); |
| } |
| log.error(e.getLocalizedMessage()+e.getCause()); |
| return false; |
| } |
| if(direction == Direction.EXPORT) { |
| int openTry = 0; |
| file = null; |
| URI uri = null; |
| try { |
| uri = fileURL.toURI(); |
| } catch (URISyntaxException e) { |
| log.error(e.getLocalizedMessage()+e.getCause()); |
| 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) { |
| log.error(e.getLocalizedMessage()+e.getCause()); |
| return false; |
| } |
| } catch (IOException e) { |
| log.error(e.getLocalizedMessage()+e.getCause()); |
| return false; |
| } |
| }while(file == null); |
| out = new BufferedOutputStream(file); |
| } |
| return true; |
| ''' |
| return body |
| } |
| |
| /** |
| * use smooks 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 performSmooks(DataInterchange dataInterchange) { |
| var firstEntity = (dataInterchange.path.iterator.next as DataInterchangeBean) |
| var body = ''' |
| if(!init(getDirection())) { |
| 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); |
| } |
| // execute the smooks filtering |
| JavaResult result = new JavaResult(); |
| InputStream in = fileURL.openStream(); |
| byte[] contents = StreamUtils.readStream(in); |
| setLength(contents.length); |
| setAvgElementSize(«IF dataInterchange.elementSize==0»10«ELSE»«dataInterchange.elementSize»«ENDIF»); |
| StreamSource source = new StreamSource(new ByteArrayInputStream(contents)); |
| ''' |
| for (path:dataInterchange.path) { |
| for (lookup:path.lookup) { |
| if (lookup.cached) { |
| body = ''' |
| «body» |
| em.setProperty(PersistenceUnitProperties.CACHE_SIZE_+"«lookup.entity.fullyQualifiedName»", "«lookup.cacheSize»"); |
| ''' |
| } |
| } |
| } |
| body = ''' |
| «body» |
| PersistenceUtil.setDAORegister(executionContext, new EntityManagerRegister(em)); |
| // execute smooks filtering |
| if (log.isDebugEnabled()) log.debug("filtering starts"); |
| setProgressIndeterminated(false); |
| if (importListener != null) { |
| importListener.notifyInitializationStep("datainterchange Warehouses load..", 0.4, 0.47, 0, 0); |
| } |
| smooks.filterSource(executionContext, source, result); |
| if (importListener != null) { |
| importListener.notifyInitializationStep("datainterchange Warehouses load...", 0.4, 0.48, 0, 0); |
| } |
| if (log.isDebugEnabled()) log.debug("smooks filtering finished"); |
| ''' |
| if (firstEntity.recordList) { |
| body = ''' |
| «body» |
| // retrieve bean list |
| List<«firstEntity.entity.fullyQualifiedName»> «firstEntity.entity.name.toFirstLower»List = Arrays.asList((«firstEntity.entity.fullyQualifiedName»[]) result.getBean("«firstEntity.entity.name»List")); |
| // persist |
| em.getTransaction().begin(); |
| if (log.isDebugEnabled()) log.debug("persisting results"); |
| int total = «firstEntity.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(«firstEntity.entity.fullyQualifiedName» «firstEntity.entity.name.toFirstLower»:«firstEntity.entity.name.toFirstLower»List) { |
| try { |
| em.persist(«firstEntity.entity.name.toFirstLower»); |
| } |
| catch (ConstraintViolationException cve) { |
| log.error("«firstEntity.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» |
| // retrieve the root bean |
| «firstEntity.entity.fullyQualifiedName» «firstEntity.entity.name.toFirstLower» = («firstEntity.entity.fullyQualifiedName») result.getBean("«firstEntity.entity.name»"); |
| // persist |
| em.getTransaction().begin(); |
| if (log.isDebugEnabled()) log.debug("persisting results"); |
| em.persist(«firstEntity.entity.name.toFirstLower»); |
| if (log.isDebugEnabled()) log.debug("committing results"); |
| em.getTransaction().commit(); |
| ''' |
| } |
| if (firstEntity.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 «firstEntity.entity.name» set «firstEntity.latestProperty.name» = 0").executeUpdate(); |
| em.createQuery("update «firstEntity.entity.name» set «firstEntity.latestProperty.name» = 1 where «»id= :id").setParameter("id", «firstEntity.entity.name.toFirstLower».getId()).executeUpdate(); |
| if (log.isDebugEnabled()) log.debug("committing mark"); |
| em.getTransaction().commit(); |
| ''' |
| } |
| if (dataInterchange.refreshEnabled) { |
| body = ''' |
| «body» |
| if(getEventBroker()!=null) { |
| getEventBroker().send(EventBrokerMsg.REFRESH_VIEW+"«dataInterchange.refresh»", "*"); |
| } |
| ''' |
| } |
| body = ''' |
| «body» |
| if (log.isDebugEnabled()) log.debug("results persisted"); |
| ''' |
| var iter = dataInterchange.path.iterator |
| var root = (iter.next as DataInterchangeBean).entity |
| body = ''' |
| «body» |
| } else { |
| if (log.isDebugEnabled()) log.debug("prepare export"); |
| ««« «IF dataInterchange.fileEndpoint instanceof DataInterchangeFileXML» |
| ««« // Create and initilise the XMLBinding instance... |
| ««« xmlBinding = new XMLBinding(smooks); |
| ««« xmlBinding.intiailize(); |
| ««« xmlBinding.setOmitXMLDeclaration(true); |
| ««« «ENDIF» |
| ««« «dataInterchange.buildEntityGraph(iter, root)» |
| int pageNumber = 1; |
| int pageSize = 1000; |
| 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(«firstEntity.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<«firstEntity.entity.fullyQualifiedName»> criteriaQuery = criteriaBuilder.createQuery(«firstEntity.entity.fullyQualifiedName».class); |
| Root<«firstEntity.entity.fullyQualifiedName»> from = criteriaQuery.from(«firstEntity.entity.fullyQualifiedName».class); |
| /* ... not necessary due to eager loading of entities via JPA ... «dataInterchange.buildJoins(iter, root)» ...*/ |
| CriteriaQuery<«firstEntity.entity.fullyQualifiedName»> select = criteriaQuery.multiselect(from); |
| |
| TypedQuery<«firstEntity.entity.fullyQualifiedName»> typedQuery = em.createQuery(select); |
| ««« typedQuery.setHint(QueryHints.JPA_LOAD_GRAPH, «firstEntity.entity.name.toFirstLower»Graph); |
| setProgressIndeterminated(false); |
| while (pageNumber < count.intValue()) { |
| if (log.isDebugEnabled()) log.debug("fetch and process entry "+pageNumber+" to "+(pageNumber+pageSize)); |
| typedQuery.setFirstResult(pageNumber - 1); |
| typedQuery.setMaxResults(pageSize); |
| List<«firstEntity.entity.fullyQualifiedName»> queryResults = typedQuery.getResultList(); |
| ««« «IF dataInterchange.fileEndpoint instanceof DataInterchangeFileCSV» |
| StringWriter writer = new StringWriter(); |
| smooks.filterSource(executionContext, new JavaSource(queryResults), new StreamResult(writer)); |
| out.write(writer.toString().getBytes()); |
| ««« «ELSEIF dataInterchange.fileEndpoint instanceof DataInterchangeFileXML» |
| ««« for(«firstEntity.entity.fullyQualifiedName» row:queryResults) { |
| ««« String outXML = xmlBinding.toXML(row); |
| ««« out.write(outXML.getBytes()); |
| ««« } |
| ««« JAXBContext jc = JAXBContext.newInstance(«firstEntity.entity.fullyQualifiedName».class); |
| ««« Marshaller marshaller = jc.createMarshaller(); |
| ««« marshaller.marshal(queryResults, out); |
| ««« «ENDIF» |
| pageNumber += pageSize; |
| } |
| if (log.isDebugEnabled()) log.debug("export finished"); |
| } |
| ''' |
| body = ''' |
| «body» |
| } catch (Exception e) { |
| log.error("«dataInterchange.name»: "+e.getLocalizedMessage()+e.getCause(), e); |
| } finally { |
| if(file != null) { |
| try { |
| out.close(); |
| file.close(); |
| } catch (IOException e) { |
| log.error(e.getLocalizedMessage()+e.getCause()); |
| } |
| } |
| smooks.close(); |
| if(getEventBroker()!=null) { |
| UI.getCurrent().setPollInterval(pollingInterval); |
| } |
| // close everything |
| if (em != null) { |
| em.close(); |
| } |
| if (log.isDebugEnabled()) log.debug("datainterchange finished"); |
| } |
| ''' |
| return body |
| } |
| |
| /** |
| * This seems to be not necessary, because JPA seems to load the entities eager itself! |
| * With this functionality active, the sql result set would contain all root entities multiple times! |
| */ |
| @Deprecated |
| def buildJoins(DataInterchange interchange, Iterator<DataInterchangeBean> iter, LEntity rootEntity) { |
| var root = rootEntity |
| var body = "" |
| if(iter.hasNext) { |
| body = '''«body»from''' |
| } |
| while(iter.hasNext) { |
| var entity = (iter.next as DataInterchangeBean).entity |
| for(f:root.features) { |
| if (f instanceof LReference && f.toMany && f.type instanceof LEntity && f.type.toName.equals(entity.toName)) { |
| // one to many for the entity in sequence is found |
| body = '''«body».fetch("«f.name»", JoinType.LEFT)''' |
| } |
| } |
| root = entity |
| } |
| if(!body.empty) { |
| body = body + ";" |
| } |
| 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))); |
| } |
| }''' |
| } |