httpURLconnection实现RCP更新

使用eclipse开发RCP系统,如果需要系统保持更新,不可避免的需要实现RCP的更新功能。

对于教程上RCP更新的实现的这里不赘述。本文探讨的是对于部署在支持http协议的更新服务器的RCP系统,利用http协议实现系统的更新。

大略看过一下org.eclipse.update.core及相关更新功能插件代码,基本原理是一样的,都是使用httpURL下载更新代码,并且eclipse做的功能更为强大,比如features及plugins的查找安装、低版本过滤、环境过滤、多线程下载、下载对话框、进度条、站点解析、异常等等,不过eclipse在更高的版本已经抛弃了这种更新方式。这里只是截取部分代码加上自己的理解所写。使用单线程。

背景

1.       RCP系统部署在tomcat-6.0.30服务器上.

2.       RCP系统基于features

3.       RCP系统更新内容(featuresplugins)的打包构建方式与等同于普通方式。

4.       site站点的创建可以是在eclipse创建site更新站点的方式。

使用httpUrlConnection实现下载

假定一个字符串urlString指向一个网络上的资源地址。

locationFileName是将资源下载到本地时所指定的名称。那么可以使用以下代码片段来下载一个资源。

publicstaticboolean download(String destUrl, String locationFileName)

    {

扫描二维码关注公众号,回复: 717552 查看本文章

        URL url = getURL(destUrl); //通过new URL(string)方式得到URL

        if (null == url)

        {

            returnfalse;

        }

        Downloader dl = new Downloader();

        HttpURLConnection httpUrl = dl.getURLConnection(url);

        if (null == httpUrl)

        {

            returnfalse;

        }

        BufferedInputStream bis = null;

        FileOutputStream fos = null;

        try

        {

            // 获取网络输入流

            bis = new BufferedInputStream(httpUrl.getInputStream());

            // 建立文件

            fos = new FileOutputStream(locationFileName);

 

            int size = 0;

            byte[] buf = newbyte[UpdateConstants.BUFFER_SIZE];

            // 保存文件

            while ((size = bis.read(buf)) != -1)

            {

                fos.write(buf, 0, size);

            }

            fos.close();

            bis.close();

            httpUrl.disconnect();

            returntrue;

        }

        catch (Exception e)

        {

            e.printStackTrace();

        }

        returnfalse;

}

/**

     * 功能描述 : 检测当前URL是否可连接或是否有效,

     * 最多连接网络 5 , 如果 5 次都不成功说明该地址不存在或视为无效地址.

     * @param url

     *            指定URL网络地址

     * @return String

     */

    publicsynchronized HttpURLConnection getURLConnection(URL url)

    {

        int counts = 0;

        while (counts++ < 5)

        {

            try

            {

                HttpURLConnection connection = (HttpURLConnection)url.openConnection();

                if (200 == connection.getResponseCode())

                {

                    return connection;

                }

            }

            catch (IOException ex)

            {

                continue;

            }

        }

        System.out.println(no connect);

        returnnull;

    }

实现RCP更新

1.       远程服务器是url=http://10.80.21.10:8080/sdfx

2.       站点的更新配置文件是site.xml.

3.       本地客户端的feature都在features/文件夹下,plugin都在plugins/文件夹下。

 

第一步,找服务器上的feature

触发更新操作后,首先通过httpURLConnection(url+”/site.xml”)指定site.xml文件读入一个新建缓冲输入流如下:

// 获取网络输入流

            bis = new BufferedInputStream(httpUrl.getInputStream());

            DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();

            document = parser.parse(bis);

site.xml文件格式固定,我们通过document解析这个文件,得到我们需要更新的feature的列表。我们得到了这些feature的名称,也就得到了他们的绝对URL路径。

第二步,判断是否需要更新

将第一步得到的featureList中的元素与本地的所有的localFeatureList中的元素通过名称中的id部分一一对比,如果找到相同的idfeature在服务器上有更新的版本,那么久认为这个站点是有更新的内容的。

第三步,下载每一个feature

在第一步中找到了许多feature,经过第二步过滤后,对剩下的feature进行下载,并放到本地的feature目录下。下载到本地后feature名称沿用。这里,关键的是featureURL路径需要构建正确。下载的代码亦然如上。要注意的是下载待本地的feature文件是一个jar包,需要通过解压jar来获得里面的信息。通过unjar方法来做到上述(解压后删除源文件)。

/**

     * 解压

     * @param fileName

     * @param locationPath

     * @return

     */

    privateboolean unJar(String fileName, String locationPath)

    {

        File file = new File(fileName);

        try

        {

            JarFile jarFile = new JarFile(file);

            unzip(jarFile, locationPath, 8192);

            jarFile.close();

        }

        catch (IOException e)

        {

            e.printStackTrace();

            returnfalse;

        }

        if (file.exists())

        {

            file.delete();

        }

        returntrue;

    }

 

    /**

     * 解压缩zip格式的压缩文件。

     * @param zipFile zip压缩包

     * @param localPath 解压的目的地

     * @param bufferSize 解压过程中使用的buffer的大小

     */

    publicstaticvoid unzip(ZipFile zipFile, String localPath, int bufferSize)

    {

        byte[] buffer = newbyte[bufferSize];

        ZipInputStream zip = null;

        ZipEntry zipEntry = null;

        try

        {

            zip = new ZipInputStream(new FileInputStream(zipFile.getName()));

            while ((zipEntry = zip.getNextEntry()) != null)

            {

                File file = new File(localPath, zipEntry.getName()).getAbsoluteFile();

                if (zipEntry.isDirectory())

                {

                    file.mkdirs();

                }

                else

                {

                    File parent = file.getParentFile();

                    if (!parent.exists())

                    {

                        parent.mkdirs();

                    }

                    file.createNewFile();

                    long size = zipEntry.getSize();

                    FileOutputStream fos = null;

                    try

                    {

                        fos = new FileOutputStream(file);

                        int readLen = -1;

                        while (size != 0)

                        {

                            readLen = zip.read(buffer);

                            size -= readLen;

                            if (readLen != -1)

                            {

                                fos.write(buffer, 0, readLen);

                            }

                        }

                    }

                    finally

                    {

                        if (fos != null)

                        {

                            fos.close();

                        }

                    }

                }

            }

        }

        catch (FileNotFoundException e)

        {

            e.printStackTrace();

        }

        catch (IOException e)

        {

            e.printStackTrace();

        }

        finally

        {

            try

            {

                if (zip != null)

                {

                    zip.close();

                }

            }

            catch (IOException e)

            {

                e.printStackTrace();

            }

        }

}

第四步,解析feature.xml文件找plugin

解压后,在文件夹中有固定名称为feature.xml文件,我们来解析这个文件。解析后我们得到一个plugins的信息列表。我们得到了这个列表,也就知道了需要下载的plugins的绝对URL

第五步,下载每一个plugin

对于每一个plugin信息,检查这个plugin是否是一个第三方的依赖插件(我们只用到了某一个功能),如果是并且本地已经有了该插件,我们可以忽略。而,如果这个插件需要依赖第三方的插件,还需要检查这个插件依赖的插件是否已经存在于本地客户端中了,如果没有,则不可以安装该插件(这里有瑕疵, 就是要求必须要先安装依赖插件)。

       如果上面的条件已经具备,下面就是需要构建一个指向该pluginURL。然后下载这个plugin。下载成功后,我们还需要根据feature中的该pluginunpack属性来确认该plugin是否需要解压。解压过程如上。

在下载每一个feature中的plugin之前我们需要做一个list来存放我们已经下载plugin,用来保证在某一个plugin下载失败时,该feature全部回滚。

其他

在打包构建时,我们还可以在feature工程中打包一个updateConfig.ini文件,这个文件中记录本次更新中需要删除的一些插件(防止插件扩展了同一个扩展点,但是这个扩展点又不允许同时有两个扩展的冲突)、需要更新的第三方插件、是不是替换本地客户端的某些资源文件、是不是需要二次启动。

       通过配置该文件,我们能修改客户端的某些配置文件(如config.ini),覆盖资源文件(xmlxlsRCP系统工作过程中所需要的),删除一些插件(给系统瘦身,RCP系统的普通更新方式是增量更新,不删除过时的插件)、以及是否需要重启动。

       重启动:有些资源或功能不能通过在更新中来完成,比如config.ini文件需要重写时,如果本地客户端旧代码中没有在更新时就修改config.ini的功能代码,而是想通过刚刚更新下去的代码来在重启时来修改config.ini文件,就需要二次启动。因为在eclipse启动时,eclipse本身首先来加载config.ini文件,系统启动进入到我们能控制的代码时,再修改config.ini文件已经不起作用(如果不重启的话),因此我们可以在主插件启动时,检测updateConfig.ini文件,看其是否指明了在启动时需要做的工作(为防止每次都重启,可以通过修改updateConfig.ini中的属性或是有无unpdateConfig.ini文件来判定)。

猜你喜欢

转载自sdfx.iteye.com/blog/1885775
今日推荐