kettle插件——实现资源库中JOB和其关联的脚本的下载

1、 设计需求:

 现项目基于Kettle采集各个节点前置机数据到数据中心并且表结构是一致的。每台前置机上安装部署kettle运行JOB,定时采集数据到数据中心。开发的脚本除了前置数据库连接不一致外,其他的都是一样的。若是为每个节点开发JOB和其关联的Trans,开发和维护都有很大的工作量。所以设计一个下载JOB和其关联的脚本组件实现,下载采集的JOB,并能够实现脚本之间关联。

2、 实现过程:

 在Kettle Spoon 设计器中已经实现了该功能。如下图:

Export all Linked resources to XML该菜单会将在spoon中当前选择的Tab的脚本,以zip压缩文件的形式导出到指定的文件夹里。

所以参考Export all Linked resources to XML菜单实现过程,来设计自己的脚本下载。

(1)首先在kettle源码中查找该功能的实现类和方法。

   在org.pentaho.di.ui.spoon.Spoon.java类中找到exportAllXMLFile()方法。该方法实现了这个菜单功能。

 

/**
	 * Export this job or transformation including all depending resources to a single zip file.
	 */
	public void exportAllXMLFile() {

		ResourceExportInterface resourceExportInterface = getActiveTransformation();
		if (resourceExportInterface==null) resourceExportInterface=getActiveJob();
		if (resourceExportInterface==null) return; // nothing to do here, prevent an NPE
		
		// ((VariableSpace)resourceExportInterface).getVariable("Internal.Transformation.Filename.Directory");
		
		// Ask the user for a zip file to export to:
		//
		try {
			String zipFilename = null;
			while (Const.isEmpty(zipFilename)) {
				FileDialog dialog = new FileDialog(shell, SWT.SAVE);
				dialog.setText(Messages.getString("Spoon.ExportResourceSelectZipFile"));
				dialog.setFilterExtensions(new String[] {"*.zip;*.ZIP", "*"});
				dialog.setFilterNames(new String[] { Messages.getString("System.FileType.ZIPFiles"), Messages.getString("System.FileType.AllFiles"), });
				setFilterPath(dialog);
				if (dialog.open()!=null)
				{
					lastDirOpened = dialog.getFilterPath();
					zipFilename = dialog.getFilterPath()+Const.FILE_SEPARATOR+dialog.getFileName();
					FileObject zipFileObject = KettleVFS.getFileObject(zipFilename);
					if (zipFileObject.exists()) {
						MessageBox box = new MessageBox(shell, SWT.YES | SWT.NO | SWT.CANCEL);
						box.setMessage(Messages.getString("Spoon.ExportResourceZipFileExists.Message", zipFilename));
						box.setText(Messages.getString("Spoon.ExportResourceZipFileExists.Title"));
						int answer = box.open();
						if (answer==SWT.CANCEL) return;
						if (answer==SWT.NO) zipFilename = null;
					}
				} else {
					return;
				}
			}
			
			// Export the resources linked to the currently loaded file...
			//
			TopLevelResource topLevelResource = ResourceUtil.serializeResourceExportInterface(zipFilename, resourceExportInterface, (VariableSpace)resourceExportInterface, rep);
			String message = ResourceUtil.getExplanation(zipFilename, topLevelResource.getResourceName(), resourceExportInterface);
							
			EnterTextDialog enterTextDialog = new EnterTextDialog(shell, "Resource serialized", "This resource was serialized succesfully!", message);
			enterTextDialog.setReadOnly();
			enterTextDialog.open();
		} catch(Exception e) {
			new ErrorDialog(shell, "Error", "Error exporting current file", e);
		}
	}

通过这个方法,可以发现其调用了ResourceExportInterface、ResourceUtil这两个重要的类。

ResourceExportInterface——这是一个资源导出的接口,JobMeta、TransMeta都实现了该接口,所以在查看JobMeta、TransMeta实现的的方法。

ResourceUtil——将脚本导出到zip压缩文件的实现类,其实现方法如下:

/**
	 * Serializes the referenced resource export interface (Job, Transformation, Mapping, Step, Job Entry, etc) to a ZIP file.
	 * 
	 * @param zipFilename The ZIP file to put the content in
	 * @param resourceExportInterface the interface to serialize
	 * @param space the space to use for variable replacement
	 * @param repository the repository to load objects from (or null if not used)
	 * @param injectXML The XML to inject into the resulting ZIP archive (optional, can be null)
	 * @param injectFilename The name of the file for the XML to inject in the ZIP archive (optional, can be null)
	 * @return The full VFS filename reference to the serialized export interface XML file in the ZIP archive.
	 * @throws KettleException in case anything goes wrong during serialization
	 */
	public static final TopLevelResource serializeResourceExportInterface(String zipFilename, ResourceExportInterface resourceExportInterface, VariableSpace space, Repository repository, String injectXML, String injectFilename) throws KettleException {
		ZipOutputStream out = null;
		
		try {
			Map<String, ResourceDefinition> definitions = new HashMap<String, ResourceDefinition>();
			
			// In case we want to add an extra pay-load to the exported ZIP file...
			//
			if (injectXML!=null) {
				ResourceDefinition resourceDefinition = new ResourceDefinition(injectFilename, injectXML);
				definitions.put(injectFilename, resourceDefinition);
			}
			
			ResourceNamingInterface namingInterface = new SequenceResourceNaming();
		
			String topLevelResource = resourceExportInterface.exportResources(space, definitions, namingInterface, repository);
			
			if (topLevelResource!=null && !definitions.isEmpty()) {
				// Create the ZIP file...
				//
				FileObject fileObject = KettleVFS.getFileObject(zipFilename);

				// Store the XML in the definitions in a ZIP file...
				//
				out = new ZipOutputStream(KettleVFS.getOutputStream(fileObject, false));
				out.setEncoding("utf-8");
				for(String filename : definitions.keySet()) {
					
					ResourceDefinition resourceDefinition = definitions.get(filename);
					
					ZipEntry zipEntry = new ZipEntry(resourceDefinition.getFilename());
					String comment = Messages.getString("ResourceUtil.SerializeResourceExportInterface.ZipEntryComment.OriginatingFile", filename, Const.NVL(resourceDefinition.getOrigin(), "-"));
					zipEntry.setComment(comment);
					out.putNextEntry(zipEntry);
					out.write(resourceDefinition.getContent().getBytes("utf-8"));
					out.closeEntry();
				}
				String zipURL = fileObject.getName().toString();
				return new TopLevelResource(topLevelResource, zipURL, "zip:"+zipURL+"!"+topLevelResource);
			} else {
				throw new KettleException(Messages.getString("ResourceUtil.Exception.NoResourcesFoundToExport"));
			}
		}
		catch(Exception e) {
			throw new KettleException(Messages.getString("ResourceUtil.Exception.ErrorSerializingExportInterface",resourceExportInterface.toString()), e);
		} 
		finally {
			if (out!=null) {
				try {
					out.close();
				} catch (IOException e) {
					throw new KettleException(Messages.getString("ResourceUtil.Exception.ErrorClosingZipStream", zipFilename));
				}
			}
		}
	}

  (2)通过读取源码之后,发现了其实现的过程,可以参考源码来实现自己的组件。Job plugin开发不写了。这里只是简单将方法贴出来:

public Result execute(Result previousResult, int nr, Repository rep, Job parentJob)
	{
		Result result = previousResult;
		result.setNrErrors(1);
		result.setResult( false );
		String realrepName=environmentSubstitute(repositoryname);
		String realusername=environmentSubstitute(username);
		String realpassword=environmentSubstitute(password);
		String realJobRepositoryPath=environmentSubstitute(directoryPath);
		if(realJobRepositoryPath == null) return result;
		String realJobDir = realJobRepositoryPath.substring(0, realJobRepositoryPath.lastIndexOf("/"));
		String realJobName =realJobRepositoryPath.substring(realJobRepositoryPath.lastIndexOf("/")+1,realJobRepositoryPath.length());
		String realoutfilename=environmentSubstitute(targetDirectoryPath);
		String realfindDatabaseName =environmentSubstitute(findDatabaseName);
		String realoutconnectname=environmentSubstitute(connectname);
		String realoutdbtype=environmentSubstitute(dbtype);
		String realoutdbaccess=environmentSubstitute(dbaccess);
		String realoutdbHost=environmentSubstitute(dbHost);
		String realoutdbname=environmentSubstitute(dbname);
		String realoutdbport=environmentSubstitute(dbport);
		String realoutdbuser=environmentSubstitute(dbuser);
		String realoutdbpassword=environmentSubstitute(dbpassword);
		try
		{
			// 连接资源库
			connectRep(log,realrepName, realJobDir, realusername, realpassword);
			// 创建新的数据对象用于替换Trans脚本中前置机的数据库对象。实现脚本数据连接的变动。
			DatabaseMeta clientDb = new DatabaseMeta(realoutconnectname,realoutdbtype,realoutdbaccess,realoutdbHost,realoutdbname,realoutdbport,realoutdbuser,realoutdbpassword);
			//导出Job和其关联的脚本到指定的目录
			exportAllXMLFile(realJobName,realoutfilename,realfindDatabaseName,clientDb);
			
			result.setResult(true);
		}catch(Exception e)
		{
			log.logError(toString(), Messages.getString("JobExportRepository.UnExpectedError",e.toString()));
			log.logError(toString(), "Stack trace: "+Const.CR+Const.getStackTracker(e));
		}finally
		{
			if(this.rep!=null) 
			{
				this.rep.disconnect();
				this.rep=null;
			}
			if(this.repinfo!=null) this.repinfo=null;
			if(this.userinfo!=null) this.userinfo=null;
			if(this.repsinfo!=null) 
			{
				this.repsinfo.clear();
				this.repsinfo=null;
			}
		}

		return result;
	}

public void exportAllXMLFile(String realJobName,String DirectoryPath,String findDatabaseName,DatabaseMeta databaseMeta) throws Exception {
		ResourceExportInterface resourceExportInterface = null;
		try {
			resourceExportInterface = new JobMeta(log,rep,realJobName,dir);
		} catch (Exception e) {
			log.logError(toString(), Messages.getString("JobExportRepository.UnExpectedError", e.toString()));
			log.logError(toString(), "Stack trace: " + Const.CR+ Const.getStackTracker(e));
		} 
		if (resourceExportInterface == null)
			return; // nothing to do here, prevent an NPE
			if(!Const.isEmpty(DirectoryPath)) {
				ResourceUtil.serializeResourceExportInterface(DirectoryPath,findDatabaseName,databaseMeta,resourceExportInterface,(VariableSpace) resourceExportInterface, rep);
			}

	}


 

3、 效果预览:

 

4、插件说明

   (1)选择指定Job,填写前置机数据库信息,运行Job会,会从资源库中下载指定的job和其关联的脚本。如job 中transformation步骤中的trans,并自动更改transformation步骤中选定的tran脚本文件为下载目录中ktr文件。

  (2)下载过的脚本不要在连接资源库的情况下保存,否则会把资源库中的脚本覆盖掉。在进行下载脚本的时候,就会报错。这是因为转换文件名不再为空,kettle优先使用这个设置,在进行下载时找不到ktr文件而报错。

5、插件下载

 http://download.csdn.net/detail/jdk2006/4514371

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值