commit e16ec06d0a19abeb613328bc01e002fc2b149a2d Author: rinoux <rinoux@foxmail.com> Date: Fri Sep 7 16:18:29 2018 +0800 REPORT-10696 hdfs资源仓库插件上传 diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..e0bf2d8 --- /dev/null +++ b/build.xml @@ -0,0 +1,120 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<project basedir="." default="jar" name="plugin"> + <!-- JDK路径,根据自己机器上实际位置修改--> + <property name="jdk.home" value="/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home"/> + + <property name="libs" value="${basedir}/lib"/> + <property name="publicLibs" value=""/> + <property name="destLoc" value="."/> + <property name="classes" value="classes"/> + <xmlproperty file="${basedir}/plugin.xml"/> + <property name="current-version" value="${plugin.version}"/> + + <!-- 插件版本--> + <property name="plugin-version" value="${current-version}"/> + <!-- 插件名字--> + <property name="plugin-name" value="hdfs-repository"/> + <property name="plugin-jar" value="fr-plugin-${plugin-name}-${plugin-version}.jar"/> + + <target name="prepare"> + <delete dir="${classes}"/> + <delete dir="fr-plugin-${plugin-name}-${plugin-version}"/> + <xmlproperty file="${basedir}/plugin.xml"/> + <delete dir="${destLoc}/${plugin.name}"/> + </target> + <path id="compile.classpath"> + <fileset dir="${libs}"> + <include name="**/*.jar"/> + </fileset> + <fileset dir="${publicLibs}"> + <include name="**/*.jar"/> + </fileset> + </path> + <patternset id="resources4Jar"> + <exclude name="**/.settings/**"/> + <exclude name=".classpath"/> + <exclude name=".project"/> + + <exclude name="**/*.java"/> + <exclude name="**/*.db"/> + <exclude name="**/*.g"/> + <exclude name="**/package.html"/> + </patternset> + <target name="copy_resources"> + <echo message="从${resources_from}拷贝图片,JS,CSS等资源文件"/> + <delete dir="tmp"/> + <copy todir="tmp"> + <fileset dir="${resources_from}\src"> + <patternset refid="resources4Jar"/> + </fileset> + </copy> + <copy todir="${classes}"> + <fileset dir="tmp"/> + </copy> + <delete dir="tmp"/> + </target> + <target name="compile_javas"> + <echo message="编译${compile_files}下的Java文件"/> + <javac destdir="${classes}" debug="false" optimize="on" source="${source_jdk_version}" + target="${target_jdk_version}" + fork="true" memoryMaximumSize="512m" listfiles="false" srcdir="${basedir}" + executable="${compile_jdk_version}/bin/javac"> + <src path="${basedir}/src"/> + <exclude name="**/.svn/**"/> + <compilerarg line="-encoding UTF8 "/> + <classpath refid="compile.classpath"/> + </javac> + </target> + + <target name="jar_classes"> + <echo message="打Jar包:${jar_name}"/> + <delete file="${basedir}/${jar_name}"/> + <unjar dest="${classes}"> + <fileset dir="${libs}" includes="hdfs-all-2.9.0.jar"/> + </unjar> + <jar jarfile="${basedir}/${jar_name}"> + <fileset dir="${classes}"> + </fileset> + </jar> + </target> + + <target name="super_jar" depends="prepare"> + <antcall target="copy_resources"> + <param name="resources_from" value="${basedir}"/> + </antcall> + <antcall target="compile_javas"> + <param name="source_jdk_version" value="1.6"/> + <param name="target_jdk_version" value="1.6"/> + <param name="compile_jdk_version" value="${jdk.home}"/> + <param name="compile_files" value="${basedir}/src"/> + </antcall> + <echo message="compile plugin success!"/> + + <antcall target="jar_classes"> + <param name="jar_name" value="${plugin-jar}"/> + </antcall> + <delete dir="${classes}"/> + + </target> + <target name="jar" depends="super_jar"> + <antcall target="zip"/> + </target> + + <target name="zip"> + <property name="plugin-folder" value="fr-plugin-${plugin-name}-${plugin-version}"/> + <echo message="----------zip files----------"/> + <mkdir dir="${plugin-folder}"/> + <copy todir="${plugin-folder}"> + <fileset dir="."> + <include name="${plugin-jar}"/> + <include name="plugin.xml"/> + </fileset> + </copy> + <zip destfile="${basedir}/${plugin-folder}.zip" basedir="."> + <include name="${plugin-folder}/*.jar"/> + <include name="${plugin-folder}/plugin.xml"/> + </zip> + <xmlproperty file="${basedir}/plugin.xml"/> + <move file="${plugin-folder}.zip" todir="${destLoc}/${plugin.name}"/> + </target> +</project> \ No newline at end of file diff --git a/img/db_fields.png b/img/db_fields.png new file mode 100644 index 0000000..e24b591 Binary files /dev/null and b/img/db_fields.png differ diff --git a/img/set.png b/img/set.png new file mode 100644 index 0000000..a2c16c7 Binary files /dev/null and b/img/set.png differ diff --git a/lib/hdfs-all-2.9.0.jar b/lib/hdfs-all-2.9.0.jar new file mode 100644 index 0000000..f458e5a Binary files /dev/null and b/lib/hdfs-all-2.9.0.jar differ diff --git a/plugin.xml b/plugin.xml new file mode 100644 index 0000000..5da4575 --- /dev/null +++ b/plugin.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<plugin> + <id>com.fr.plugin.hdfs.repository</id> + <name><![CDATA[HDFS资源仓库]]></name> + <active>yes</active> + <hidden>no</hidden> + <version>1.0</version> + <env-version>10.0</env-version> + <jartime>2018-03-13</jartime> + <vendor>rinoux</vendor> + <description><![CDATA[描述]]></description> + <change-notes><![CDATA[无]]></change-notes> + <!--主包--> + <main-package>com.fr.plugin</main-package> + <!--功能记录点类--> + <function-recorder class="com.fr.plugin.hdfs.repository.HDFSFactoryProvider"/> + <extra-core> + <ResourceRepositoryFactoryProvider class="com.fr.plugin.hdfs.repository.HDFSFactoryProvider"/> + </extra-core> +</plugin> \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ffdddbd --- /dev/null +++ b/readme.md @@ -0,0 +1,22 @@ +# 开发和测试使用说明 +- 1、hdfs仓库插件是平台文件服务器的扩展,首先需要正常方式安装插件; +- 2、在没有平台可视化设置之前,可以通过添加数据库字段来开启hdfs; + +> 上图中的ResourceModuleConfig.profiles.HDFS_TEST.workroots.[你的机器id(可以拷贝表中LOCAL_ENV的)]为hdfs的工作路径。 +> host设置为Hadoop的hdfs地址,比如默认localhost,port为hdfs端口(默认9000)。 +> 如果有用户组设置还需要对应用户名username。 +- 3、添加数据库字段设置仓库为hdfs: + +- 4、启动设计器或者平台 + +- 5、其它说明: + +改数据库太麻烦,可以直接在适当的地方(比如com.fr.io.ResourceRepositoryActivator.doExtra()方法末尾)添加代码 +``` Map<String, Object> hdfsConfig = new HashMap<String, Object>(); + hdfsConfig.put("host", "localhost"); + hdfsConfig.put("port", 9000); + try { + ProfileFactory.create("HDFS", "HDFS_TEST", "/app", true, hdfsConfig).install().apply(); + } catch (RepositoryException e) { + e.printStackTrace(); + } \ No newline at end of file diff --git a/src/com/fr/plugin/hdfs/repository/HDFSFactoryProvider.java b/src/com/fr/plugin/hdfs/repository/HDFSFactoryProvider.java new file mode 100644 index 0000000..b5d9e22 --- /dev/null +++ b/src/com/fr/plugin/hdfs/repository/HDFSFactoryProvider.java @@ -0,0 +1,80 @@ +package com.fr.plugin.hdfs.repository; + +import com.fr.event.Event; +import com.fr.event.EventDispatcher; +import com.fr.event.Listener; +import com.fr.io.base.exception.RepositoryException; +import com.fr.io.base.provider.RepositoryFactoryProvider; +import com.fr.io.context.ResourceModuleContext; +import com.fr.io.context.info.InstalledComponent; +import com.fr.io.context.info.RepositoryApplyPolicy; +import com.fr.io.fun.AbstractRepositoryFactoryProvider; +import com.fr.log.FineLoggerFactory; +import com.fr.plugin.context.PluginContext; +import com.fr.plugin.hdfs.repository.core.HDFSConfig; +import com.fr.plugin.hdfs.repository.core.HDFSRepositoryFactory; +import com.fr.plugin.observer.PluginEventType; +import com.fr.plugin.transform.ExecuteFunctionRecord; +import com.fr.plugin.transform.FunctionRecorder; +import com.fr.stable.project.ProjectConstants; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Created by rinoux on 2018/8/10. + */ +@FunctionRecorder +public class HDFSFactoryProvider extends AbstractRepositoryFactoryProvider<HDFSConfig> { + + private static HDFSRepositoryFactory factory = new HDFSRepositoryFactory(); + + /* static { + Listener<PluginContext> stopListener = new Listener<PluginContext>() { + @Override + public void on(Event event, PluginContext param) { + if (param.getMarker().getPluginID().equals("com.fr.plugin.hdfs.repository")) { + try { + if (ResourceModuleContext.getCurrentRepo().getIdentity().equals(HDFSRepositoryFactory.IDENTITY)) { + ResourceModuleContext.apply(ProjectConstants.LOCAL_ENV, RepositoryApplyPolicy.EXCLUSIVE); + } + + Map<String, InstalledComponent> all = ResourceModuleContext.getInstaller().findAll(); + List<InstalledComponent> components = new ArrayList<InstalledComponent>(all.values()); + for (InstalledComponent component : components) { + if (component.getFactory().getIdentity().equals(HDFSRepositoryFactory.IDENTITY)) { + ResourceModuleContext.discard(component.getRepoName()); + ResourceModuleContext.uninstall(component.getRepoName()); + } + } + } catch (RepositoryException e) { + FineLoggerFactory.getLogger().error(e.getMessage()); + } finally { + ResourceModuleContext.removeFactory(HDFSRepositoryFactory.IDENTITY); + } + } + } + }; + + Listener<PluginContext> startListener = new Listener<PluginContext>() { + @Override + public void on(Event event, PluginContext param) { + ResourceModuleContext.getFactoryLoader().add(factory); + } + }; + + EventDispatcher.listen(PluginEventType.BeforeStop, stopListener); + EventDispatcher.listen(PluginEventType.BeforeUnInstall, stopListener); + + + EventDispatcher.listen(PluginEventType.AfterActive, startListener); + EventDispatcher.listen(PluginEventType.AfterInstall, startListener); + }*/ + + @Override + @ExecuteFunctionRecord + public RepositoryFactoryProvider<HDFSConfig> getFactory() { + return factory; + } +} diff --git a/src/com/fr/plugin/hdfs/repository/core/HDFSConfig.java b/src/com/fr/plugin/hdfs/repository/core/HDFSConfig.java new file mode 100644 index 0000000..3103ff5 --- /dev/null +++ b/src/com/fr/plugin/hdfs/repository/core/HDFSConfig.java @@ -0,0 +1,16 @@ +package com.fr.plugin.hdfs.repository.core; + +import com.fr.config.holder.Conf; +import com.fr.config.holder.factory.Holders; +import com.fr.io.config.CommonRepoConfig; + +/** + * Created by rinoux on 2018/8/10. + */ +public class HDFSConfig extends CommonRepoConfig { + public HDFSConfig() { + super(HDFSRepositoryFactory.IDENTITY); + } + + // TODO: 2018/8/10 config fields +} diff --git a/src/com/fr/plugin/hdfs/repository/core/HDFSRepositoryFactory.java b/src/com/fr/plugin/hdfs/repository/core/HDFSRepositoryFactory.java new file mode 100644 index 0000000..f35a834 --- /dev/null +++ b/src/com/fr/plugin/hdfs/repository/core/HDFSRepositoryFactory.java @@ -0,0 +1,112 @@ +package com.fr.plugin.hdfs.repository.core; + +import com.fr.general.GeneralUtils; +import com.fr.io.base.provider.impl.ConfigRepositoryFactory; +import com.fr.io.context.info.RepositoryProfile; +import com.fr.io.repository.ResourceRepository; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.StringUtils; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; + +import java.io.IOException; +import java.net.URI; + +/** + * Created by rinoux on 2018/8/10. + */ +public class HDFSRepositoryFactory extends ConfigRepositoryFactory<HDFSConfig> { + static final String IDENTITY = "HDFS"; + private static final String HDFS_SCHEMA = "hdfs://"; + private static final String DEFAULT_HOST = "localhost"; + private static final String DEFAULT_PORT = "9000"; + + + public HDFSRepositoryFactory() { + super(IDENTITY); + } + + @Override + public Class<? extends RepositoryProfile<HDFSConfig>> getProfileClass() { + return HDFSRepositoryProfile.class; + } + + @Override + public Class<HDFSConfig> getConfigClass() { + return HDFSConfig.class; + } + + @Override + public boolean verifyConfig(HDFSConfig config) { + FileSystem fileSystem = null; + try { + fileSystem = createFileSystem(config); + return fileSystem.exists(new Path("/")); + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage()); + } finally { + if (fileSystem != null) { + try { + fileSystem.close(); + } catch (IOException ignored) { + + } + } + } + return false; + } + + @Override + public ResourceRepository produce(String repoName, String workRoot, HDFSConfig config) { + return new HDFSResourceRepository(repoName, workRoot, createFileSystem(config)); + } + + + private FileSystem createFileSystem(HDFSConfig config) { + FileSystem fs; + Configuration conf = createConfiguration(); + + //根据配置生成url + String host = StringUtils.isEmpty(config.getHost()) ? DEFAULT_HOST : config.getHost(); + String port = config.getPort() == 0 ? DEFAULT_PORT : String.valueOf(config.getPort()); + + String hdfsUrl = HDFS_SCHEMA.concat(host).concat(":").concat(port); + String user = config.getUsername(); + try { + if (StringUtils.isNotEmpty(user)) { + fs = FileSystem.get(URI.create(hdfsUrl), conf, user); + } else { + fs = FileSystem.get(URI.create(hdfsUrl), conf); + } + + + return fs; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + + /** + * 初始化hadoop-hdfs配置 + * + * @return 配置 + */ + private Configuration createConfiguration() { + Configuration conf = new Configuration(true); + + //使用GeneralUtils才能加载到FileSystem实现类 + conf.setClassLoader(new ClassLoader() { + @Override + public Class<?> loadClass(String name) throws ClassNotFoundException { + return GeneralUtils.classForName(name); + } + }); + + //设置hdfs协议实现 + conf.setClass("fs.hdfs.impl", org.apache.hadoop.hdfs.DistributedFileSystem.class, FileSystem.class); + + return conf; + } +} diff --git a/src/com/fr/plugin/hdfs/repository/core/HDFSRepositoryProfile.java b/src/com/fr/plugin/hdfs/repository/core/HDFSRepositoryProfile.java new file mode 100644 index 0000000..ae5c258 --- /dev/null +++ b/src/com/fr/plugin/hdfs/repository/core/HDFSRepositoryProfile.java @@ -0,0 +1,37 @@ +package com.fr.plugin.hdfs.repository.core; + +import com.fr.config.Identifier; +import com.fr.config.holder.Conf; +import com.fr.config.holder.factory.Holders; +import com.fr.io.context.info.RepositoryProfile; + +/** + * Created by rinoux on 2018/8/10. + */ +public class HDFSRepositoryProfile extends RepositoryProfile<HDFSConfig> { + + public HDFSRepositoryProfile() { + } + + @Identifier("hdfsConfig") + private Conf<HDFSConfig> hdfsConfig = Holders.obj(null, HDFSConfig.class); + + @Override + public HDFSConfig getConfig() { + return hdfsConfig.get(); + } + + @Override + public void setConfig(HDFSConfig config) { + this.hdfsConfig.set(config); + } + + + @Override + public RepositoryProfile<HDFSConfig> clone() throws CloneNotSupportedException { + HDFSRepositoryProfile cloned = (HDFSRepositoryProfile) super.clone(); + cloned.hdfsConfig = (Conf<HDFSConfig>) this.hdfsConfig.clone(); + + return cloned; + } +} diff --git a/src/com/fr/plugin/hdfs/repository/core/HDFSResourceRepository.java b/src/com/fr/plugin/hdfs/repository/core/HDFSResourceRepository.java new file mode 100644 index 0000000..eaeb07a --- /dev/null +++ b/src/com/fr/plugin/hdfs/repository/core/HDFSResourceRepository.java @@ -0,0 +1,299 @@ +package com.fr.plugin.hdfs.repository.core; + +import com.fr.io.base.exception.ConnectionException; +import com.fr.io.repository.FineFileEntry; +import com.fr.io.repository.base.BaseResourceRepository; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.Filter; +import com.fr.workspace.resource.ResourceIOException; +import org.apache.hadoop.fs.FSDataOutputStream; +import org.apache.hadoop.fs.FileStatus; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.fs.PathFilter; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.ConnectException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by rinoux on 2018/8/10. + */ +public class HDFSResourceRepository extends BaseResourceRepository { + private FileSystem fs; + + + public HDFSResourceRepository(String repoName, String workRoot, FileSystem fs) { + super(repoName, workRoot); + this.fs = fs; + } + + + @Override + public String getSeparator() { + return "/"; + } + + @Override + public FineFileEntry getEntry(String path) { + try { + FileStatus status = fs.getFileStatus(new Path(path)); + + return convertToFineFileEntry(status); + } catch (ConnectException e) { + throw new ConnectionException(); + } catch (IOException e) { + return null; + } + } + + + private FineFileEntry convertToFineFileEntry(FileStatus status) { + FineFileEntry entry = new FineFileEntry(status.getPath().toUri().getPath()); + + entry.setDirectory(status.isDirectory()); + entry.setSize(status.getLen()); + entry.setTimestamp(status.getModificationTime()); + entry.setName(status.getPath().getName()); + + + return entry; + } + + @Override + public FineFileEntry[] listEntry(String dir) { + List<FineFileEntry> entryList = new ArrayList<FineFileEntry>(); + try { + FileStatus[] statuses = fs.listStatus(new Path(dir)); + + for (FileStatus status : statuses) { + entryList.add(convertToFineFileEntry(status)); + } + + } catch (ConnectException e) { + throw new ConnectionException(); + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + return entryList.toArray(new FineFileEntry[0]); + } + + @Override + public URL getResource(String path) { + try { + FileStatus status = fs.getFileStatus(new Path(path)); + + return new URL(status.getPath().toUri().toString()); + } catch (ConnectException e) { + throw new ConnectionException(); + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + + return null; + } + + @Override + public InputStream read(String file) throws ResourceIOException { + try { + return fs.open(new Path(file)); + } catch (ConnectException e) { + throw new ConnectionException(); + } catch (IOException e) { + return null; + } + } + + @Override + public void write(String path, byte[] data) { + OutputStream os = null; + try { + os = fs.create(new Path(path), true); + os.write(data); + } catch (ConnectException e) { + throw new ConnectionException(); + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } finally { + try { + if (os != null) { + os.flush(); + os.close(); + } + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + } + + @Override + public boolean createFile(String path) { + try { + return fs.createNewFile(new Path(path)); + } catch (ConnectException e) { + throw new ConnectionException(); + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + return false; + } + + @Override + public boolean createDirectory(String path) { + try { + return fs.mkdirs(new Path(path)); + } catch (ConnectException e) { + throw new ConnectionException(); + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + + return false; + } + + @Override + public boolean delete(String path) { + try { + return fs.delete(new Path(path), true); + } catch (ConnectException e) { + throw new ConnectionException(); + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + + return false; + } + + @Override + public boolean exist(String path) { + try { + return fs.exists(new Path(path)); + } catch (ConnectException e) { + throw new ConnectionException(); + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage()); + } + + return false; + } + + @Override + public String[] list(String dir, final Filter<String> filter) { + List<String> result = new ArrayList<String>(); + try { + FileStatus[] statuses = fs.listStatus(new Path(dir), new PathFilter() { + @Override + public boolean accept(Path path) { + return filter.accept(path.getName()); + } + }); + + for (FileStatus status : statuses) { + result.add(status.getPath().getName()); + } + + } catch (ConnectException e) { + throw new ConnectionException(); + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage()); + } + return result.toArray(new String[0]); + } + + @Override + public boolean isDirectory(String path) { + try { + return fs.isDirectory(new Path(path)); + } catch (ConnectException e) { + throw new ConnectionException(); + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + + return false; + } + + @Override + public long lastModified(String path) { + try { + return fs.getFileStatus(new Path(path)).getModificationTime(); + } catch (ConnectException e) { + throw new ConnectionException(); + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + + return 0L; + } + + @Override + public long length(String path) { + try { + return fs.getFileStatus(new Path(path)).getLen(); + } catch (ConnectException e) { + throw new ConnectionException(); + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + + return 0L; + } + + + @Override + public boolean rename(String path, String newPath) throws ResourceIOException { + try { + return fs.rename(new Path(path), new Path(newPath)); + } catch (ConnectException e) { + throw new ConnectionException(); + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage()); + } + + return false; + } + + + @Override + public void appendWrite(String file, byte[] data) throws ResourceIOException { + FSDataOutputStream out = null; + try { + out = fs.append(new Path(file)); + out.write(data); + + } catch (ConnectException e) { + throw new ConnectionException(); + } catch (IOException e) { + throw new ResourceIOException(e); + } finally { + if (out != null) { + try { + out.flush(); + out.close(); + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage()); + } + } + } + } + + + @Override + public void shutDown() { + try { + fs.close(); + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + + @Override + public String getIdentity() { + return HDFSRepositoryFactory.IDENTITY; + } + +}