Maven构建OSGI+HttpServer应用

Maven构建OSGI+HttpServer应用

官网(https://eclipse.dev/equinox/server/http_in_equinox.php)介绍有两种方式:

一种是基于”org.eclipse.equinox.http”包的轻量级实现,另一种是基于”org.eclipse.equinox.http.jetty”包(基于jetty的Servlet)实现。

使用 "org.eclipse.equinox.http" 包(例如:http-1.0.100-v20070423.jar),可以将我们自定义的服务(servlet或静态资源页面)注册到这个 HttpService 中去,实现自定义的HTTP服务。

"org.osgi.service.http" 包(例如:org.osgi.service.http-1.2.2.jar)内部会内嵌一个 HttpService Interface,而"org.eclipse.equinox.http" 包(http-1.0.100-v20070423.jar)提供了一个上述Interface的 HttpService实现类,因此,一旦这个osgi bundle (http-1.0.100-v20070423.jar)启动了,就会有一个内嵌的 http 服务被启动,默认地址是 http://localhost,端口为 80,可以通过指定参数 “org.osgi.service.http.port”来修改默认端口。

"org.eclipse.equinox.http" 包(http-1.0.100-v20070423.jar)内有一个上面那个 HttpService Interface 的实现类:

想要提供我们自定义的 HttpService服务,就要将我们的服务(servlet或静态资源页面)注册到这个 HttpService 中去,需要用到 "org.osgi.service.http" 包中的 HttpService 类的两个注册方法:

1)注册静态资源:
registerResources(String alias, String name, HttpContext httpContext)

2)注册 Servlet 类:
registerServlet(String alias, Servlet servlet, Dictionary initparams, HttpContext httpContext)

所以要想提供我自己的WebService实现,我们就需要:

提供自定义的WebService实现的步骤如下:
1)获取 httpService 对象;
2)编码提供 servlet 和 webpage 的实现;
3)将 servlet 和 webpage 注册到 HttpService 服务中去(同时指定对应的 alias);
4)访问;

新建manve项目:

创建package、class、和编码:
1)Java package:com.xxx.osgi.httpserver.demo、com.xxx.osgi.httpserver.servlet
2)Java class文件:Activator.java、MyServlet.java

Activator.java:

package com.xxx.osgi.httpserver.demo;

import com.xxx.osgi.httpserver.servlet.MyServlet;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.http.HttpContext;
import org.osgi.service.http.HttpService;

import java.util.LinkedList;
import java.util.List;

/**
 * @author Frank
 * @date 2023/12/26
 */
public class Activator implements BundleActivator {
    private static BundleContext bundleContext;
    private HttpService httpService;
    private List<Bundle> bundles;
   
    static BundleContext getBundleContext() {
        return bundleContext;
    }

    public void start(BundleContext bundleContext) throws Exception {
        Activator.bundleContext = bundleContext;
        installBundles(bundleContext, false); // install other bundles
        ServiceReference serviceReference = bundleContext.getServiceReference(HttpService.class.getName());
        httpService = (HttpService) bundleContext.getService(serviceReference);

        // 注册
        HttpContext httpContext = httpService.createDefaultHttpContext();

        // 注册静态页面,设置别名"/osgi",所有对"/osgi"的请求映射到"/webpage/index.html"
        httpService.registerResources("/osgi", "/webpage/index.html", httpContext);
        System.out.println("start ok");

        // 注册 servlet,设置servlet别名"/test",所有对'/test"的请求映射到myServlet的实现
        MyServlet myServlet = new MyServlet();
        httpService.registerServlet("/test", myServlet, null, httpContext);
    }

    public void stop(BundleContext bundleContext) throws Exception {
        installBundles(bundleContext, true); //uninstall other bundles
        httpService.unregister("/osgi");
        httpService.unregister("/test");
        Activator.bundleContext = null;
        System.out.println("stop ok");
    }

    public void installBundles(BundleContext context, boolean uninstall) {
        List<String> bundleFiles = new LinkedList<String>();
        List<Bundle> installedBundles = new LinkedList<Bundle>();
        //install my other bundles
        // System.out.printf("1 %s\n", FileLocator.getBundleFile(FrameworkUtil.getBundle(Activator.class)).getAbsolutePath());
        // System.out.printf("2 %s\n", FileLocator.getBundleFile(context.getBundle()).getAbsolutePath());
        // System.out.printf("3 %s\n", context.getBundle().getLocation());

        // String baseDir = FileLocator.getBundleFile(context.getBundle()).getParentFile().getAbsolutePath();
        String baseDir = context.getBundle().getLocation().replaceFirst("/[^/]*.jar","/");
        bundleFiles.add(baseDir + "helloworld-server-1.0.0-SNAPSHOT.jar");
        if (!uninstall) {
            // install & start bundles
            for (String bundleFile : bundleFiles) {
                try {
                    Bundle bundle = context.installBundle(bundleFile);
                    installedBundles.add(bundle);
                    bundle.start();
                } catch (BundleException e) {
                    if (!e.getMessage().contains("A bundle is already installed")) {
                        throw new RuntimeException(e);
                    }
                }
            }
            bundles = installedBundles;
            System.out.printf("all bundles (cnt = %d) installed and started!", bundles.size());
        } else {
            // stop & uninstall bundles
            for (Bundle bundle : bundles) {
                try {
                    context.getBundle(bundle.getBundleId()).stop();
                    context.getBundle(bundle.getBundleId()).uninstall();
                } catch (BundleException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.printf("all bundles (cnt = %d) stopped and uninstalled!", bundles.size());
        }
    }
}

MyServlet.java:

package com.xxx.osgi.httpserver.servlet;

import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.logging.Logger;

public class MyServlet extends HttpServlet implements Servlet {
    
    private Logger logger = Logger.getLogger(this.getClass().getName());

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("MyServlet return: Method=" + req.getMethod() + ", URI=" + req.getRequestURI());
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("MyServlet return: Method=" + req.getMethod() + ", URI=" + req.getRequestURI());
    }
}

3)创建静态页面文件:webpage/index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>jetty test</title>
</head>
<body>
<h2>OSGI HttpServer/Jetty Test</h2>
<font color="green"> register static resource/pages: </font><br>
registerResources(String alias, String name, HttpContext httpContext) <br><br>

<font color="green">register servlet class: </font><br>
registerServlet(String alias, Servlet servlet, Dictionary initparams, HttpContext httpContext)
</body>
</html>

4)创建&编辑 pom.xml 文件

pom文件中定义了OSGI框架和版本、编码中所需的依赖以及osgi menifest和osgi打包配置:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.xxx.osgi</groupId>
  <artifactId>osgi-httpserver-demo</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <packaging>bundle</packaging>

  <name>osgi-httpserver-demo</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>

    <dependency>
      <!-- 该版本 maven 仓库找不到,如果要用该版本可以在 Project Structure->Project Settings->Modules 中设置:-->
      <!-- 设置 OSGI:General->Configure OSGI Core Library->Use Library 指定本地 jar 文件静态添加 osgi lib  -->
      <!--
      <groupId>org.eclipse</groupId>
      <artifactId>osgi</artifactId>
      <version>3.18.600.v20231110-1900</version>
      <scope>provided</scope>
      -->
      <!-- 该版本maven仓库可以找到,可以用这个版本。在 pom 中指定 osgi lib 的 dependency 依赖 -->
      <groupId>org.eclipse</groupId>
      <artifactId>osgi</artifactId>
      <version>3.10.0-v20140606-1445</version>
      <scope>provided</scope>
    </dependency>

    <!-- START: httpServer required bundles -->
    <!-- org.osgi.service.cm_1.6.1.202109301733.jar -->
    <dependency>
      <groupId>org.osgi</groupId>
      <artifactId>org.osgi.service.cm</artifactId>
      <version>1.6.1</version>
    </dependency>
    <!-- javax.servlet-3.0.0.v201112011016.jar -->
    <dependency>
      <groupId>org.eclipse.jetty.orbit</groupId>
      <artifactId>javax.servlet</artifactId>
      <version>3.0.0.v201112011016</version>
    </dependency>
    <!-- http-1.0.100-v20070423.jar -->
    <dependency>
      <groupId>org.eclipse.equinox</groupId>
      <artifactId>http</artifactId>
      <version>1.0.100-v20070423</version>
    </dependency>
    <!-- org.osgi.service.http-1.2.2.jar -->
    <dependency>
      <groupId>org.osgi</groupId>
      <artifactId>org.osgi.service.http</artifactId>
      <version>1.2.2</version>
    </dependency>
    <!-- END: httpServer required bundles -->

    <!-- for: org.eclipse.core.runtime.FileLocator -->
    <!-- common-3.6.200-v20130402-1505.jar / org.eclipse.equinox.common.source_3.18.200.v20231106-1826.jar -->
    <dependency>
      <groupId>org.eclipse.equinox</groupId>
      <artifactId>common</artifactId>
      <version>3.6.200-v20130402-1505</version>
    </dependency>

  </dependencies>

  <build>
    <plugins>
      <plugin>
        <!-- osgi 打包配置,使用 maven-bundle-plugin 插件进行 osgi 打包 bundle jar -->
        <!-- 使用maven-bundle-plugin打包方式时指定manifest文件不生效,但可在 instructions 中配置 manifest 参数 -->
        <groupId>org.apache.felix</groupId>
        <artifactId>maven-bundle-plugin</artifactId>
        <version>3.5.0</version>
        <extensions>true</extensions>

        <configuration>
          <instructions>
            <!-- 把依赖的普通jar和bundle jar也一起打包进去(/lib目录下),bundle jar 服务依赖还要在 Import-Package 中指定 -->
            <Embed-Dependency>*;scope=compile|runtime</Embed-Dependency>
            <Embed-Directory>lib</Embed-Directory>
            <Embed-Transitive>true</Embed-Transitive>

            <!-- BEGIN: 把本地静态资源目录也打包进去 -->
            <Include-Resource>webpage=webpage</Include-Resource>
            <!-- END: 把本地静态资源目录webpage也打包进去(到webpage目录、相当于目录拷贝) -->

            <Bundle-ClassPath>.,{maven-dependencies}</Bundle-ClassPath>
            <Bundle-Name>${project.name}</Bundle-Name>
            <Bundle-SymbolicName>$(replace;${project.artifactId};-;_)</Bundle-SymbolicName>
            <Bundle-Version>${project.version}</Bundle-Version>
            <Bundle-Activator>com.xxx.osgi.httpserver.demo.Activator</Bundle-Activator>
            <DynamicImport-Package>*</DynamicImport-Package>
            <Import-Package>
              javax.servlet,
              javax.servlet.http,
              org.osgi.service.http;resolution:="optional"
            </Import-Package>
            <Export-Package></Export-Package>
          </instructions>
        </configuration>

      </plugin>
    </plugins>
  </build>
</project>

整体项目的代码结构如下:

准备运行依赖的bundles:

org.osgi.service.cm_1.6.1.202109301733.jar
javax.servlet-3.0.0.v201112011016.jar
org.osgi.service.http-1.2.2.jar
http-1.0.100-v20070423.jar
 

直接在 configuration/config.ini 初始化启动配置中加入依赖 bundles 或者启动 osgi 以后执行 install 安装依赖 bundles:
install plugins/org.osgi.service.cm_1.6.1.202109301733.jar
install other_bundles/javax.servlet-3.0.0.v201112011016.jar
install other_bundles/org.osgi.service.http-1.2.2.jar
install other_bundles/http-1.0.100-v20070423.jar
start 5 6 7 8 

注意,多条命名install时有先后顺序依赖,也可以放在一条命令执行多个 bundle 的install(无顺序依赖)
install plugins/org.osgi.service.cm_1.6.1.202109301733.jar other_bundles/javax.servlet-3.0.0.v201112011016.jar other_bundles/org.osgi.service.http-1.2.2.jar other_bundles/http-1.0.100-v20070423.jar
 

“org.osgi.service.http”的HttpService Interface的实现类bundle “org.eclipse.equinox.http”启动后,HttpService服务就启动了、查看HttpService监听端口已开启(如果equinox的配置文件或启动参数没有指定 org.osgi.service.http.port=8080 的话,默认是监听的是 80 端口):

项目编译打包:
执行命令打包
mvn clean package

拷贝项目编译打包生成的jar文件到osgi运行环境:

执行osgi-httpserver-demo jar包(install & start):

项目bundle 9已经启动、bundle9内代码install & start 的其他bundel 10 也都start成功,状态为ACTIVE了。

httpServer 访问测试(访问 localhost:8080/osgi 和 localhost:8080/test):
命令行访问页面:

浏览器访问页面:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/375710.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024最新CleanMyMac X优化Mac电脑系统体验分享

使用Mac电脑的用户都希望它们能够保持最佳性能。但有时&#xff0c;你可能会发现你的Mac运行变慢或响应迟缓。这可能是由于几个原因造成的&#xff0c;包括硬盘空间不足、系统缓存堆积、以及过多的启动项等。解决了这些问题&#xff0c;你可以显著提升你的Mac性能。本文将探讨导…

工程示例(LED、流水灯、蜂鸣器)

LED闪烁 #include "stm32f10x.h" // Device header #include "Delay.h"int main(void) {RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitTypeDef GPIO_InitSructure;GPIO_InitSructure.GPIO_Mode GPIO_Mode_Out_PP;GPIO…

SpringBoot+随机盐值+双重MD5实现加密登录

&#x1f3e1;浩泽学编程&#xff1a;个人主页 &#x1f525; 推荐专栏&#xff1a;《深入浅出SpringBoot》《java对AI的调用开发》 《RabbitMQ》《Spring》《SpringMVC》 &#x1f6f8;学无止境&#xff0c;不骄不躁&#xff0c;知行合一 文章目录 前言一、salt…

遗失的源代码之回归之路的探索与实践

背景 最近比较突然被安排接手一个项目,该项目的情况如下 原生和RN结合的混合开发模式组件化开发,有很多基础组件以及业务组件但是在梳理项目依赖时发现了个别组件源码不全的情况,于是写了个cli用于对比两个版本产物文件,生成差异结果以便于快速进行源码找回恢复。 结果如下…

Python tkinter (16) —— Progressbar

本文主要介绍Python tkinter 进度条Progressbar应用及示例。 目录 系列文章 进度条Progressbar 基本概念 参数&#xff1a; mode参数 基本应用 动画设计 引入time 具体实现 start/step/stop step(amount)&#xff1a; start(interval)&#xff1a; stop()&#xff…

QT 范例阅读:系统托盘 The System Tray Icon example

main.cpp QApplication app(argc, argv);//判断系统是否支持 系统托盘功能if (!QSystemTrayIcon::isSystemTrayAvailable()) {QMessageBox::critical(0, QObject::tr("Systray"),QObject::tr("I couldnt detect any system tray ""on this system.&qu…

一文掌握SpringBoot注解之@Configuration知识文集(6)

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

ionic报错:Cannot read properties of undefined (reading ‘classList‘)

报错信息&#xff1a; [ionic/vue Warning]: The view you are trying to render for path /tabs/tab1 does not have the required <ion-page> component. Transitions and lifecycle methods may not work as expected.See https://ionicframework.com/docs/vue/navig…

fx-82es软升级至fx-991es整理

fx-82es和fx-991es在硬件上采用的是相同的流水线设计。fx-82es为了降低成本或出于其他考虑&#xff0c;卡西欧在其主板上去掉了一些以微积分为主的功能 也就是说fx-82es理论上是有可能升级到fx-991es的&#xff0c;硬件上进行升级之前有人尝试成功过了&#xff0c;但是有一定风…

30s速通String——从JVM内存 到相关方法

0.深度理解String&#xff08;初学者可后面再看&#xff09; 1.JVM理解两种初始化String方式 1.1直接初始化 栈中保存变量s1,s2&#xff0c;而变量保存“abc”在方法区的地址 这里当“abc”具有唯一性&#xff0c;字符串常量区无此字符串&#xff0c;我们就产生一个新内存“…

【动态规划】【子序列除重】【C++算法】1987不同的好子序列数目

作者推荐 【动态规划】【状态压缩】【2次选择】【广度搜索】1494. 并行课程 II 本文涉及知识点 动态规划汇总 LeetCode1987:不同的好子序列数目 给你一个二进制字符串 binary 。 binary 的一个 子序列 如果是 非空 的且没有 前导 0 &#xff08;除非数字是 “0” 本身&…

EasyRecovery2024永久免费版电脑数据恢复软件下载

EasyRecovery数据恢复软件是一款非常好用且功能全面的工具&#xff0c;它能帮助用户恢复各种丢失或误删除的数据。以下是关于EasyRecovery的详细功能介绍以及下载步骤&#xff1a; EasyRecovery-mac最新版本下载:https://wm.makeding.com/iclk/?zoneid50201 EasyRecovery-win…

AD9361多片同步设计方法

本文基于ZC706FMCOMMS5的平台&#xff0c;介绍了多片AD9361同步的方法。并将该设计移植到自行设计的ZYNQ70354片AD9361(实现8路同步收发)的电路板上。本设计采用纯逻辑的方式&#xff0c;仅使用了ZYNQ芯片的PL部分。 9361多芯片同步主要包括基带同步和射频同步两大块任务。其中…

maven插件docker-maven-plugin打包镜像并发布到dockerHub

文章目录 前言一、使用maven插件制作docker镜像二、发布到dockerHub总结 前言 如果我们的项目要在docker中运行&#xff0c;那么就必须要把我们的项目生成docker镜像&#xff0c;如果要实现远程安装&#xff0c;也就必须要把镜像发布到远程仓库里&#xff0c;如果我们没有自己…

旭华智能水文遥测终端机RTU

SV-RT8588低功耗测控终端&#xff0c;可采集、存储监测点传感器/仪表数据&#xff0c;通过4G/网口等通讯方式上传至监管平台&#xff0c;产品采用高性能32位处理器和工业级无线模块&#xff0c;接口类型丰富配置灵活&#xff0c;能满足不同场景下的各种需求&#xff1b;低功耗设…

JavaEE企业级应用软件开发—Spring框架入门学习笔记(一)

一、认识框架 实际开发中&#xff0c;随着业务的发展&#xff0c;软件系统变得越来越复杂&#xff0c;如果所有的软件都从底层功能开始开发&#xff0c;那将是一个漫长而繁琐的过程。此外&#xff0c;团队协作开发时&#xff0c;由于没有统一的调用规范&#xff0c;系统会出现大…

Vue3.4+element-plus2.5 + Vite 搭建教程整理

一、 Vue3Vite 项目搭建 说明&#xff1a; Vue3 最新版本已经基于Vite构建&#xff0c;关于Vite简介&#xff1a;Vite 下一代的前端工具链&#xff0c;前端开发与构建工具-CSDN博客 1.安装 并 创建Vue3 应用 npm create vuelatest 创建过程可以一路 NO 目前推荐使用 Vue R…

Django前后端分离之后端实践2

小实践&#xff1a;实现用户登录、注销及ORM管理功能、事务开启小实践 models.py class Books(models.Model):id models.CharField(primary_keyTrue,max_length20,verbose_name"图书ID")name models.CharField(max_length20,verbose_name图书名称)status models…

MySQL 小技巧:利用 xtrabackup 完全备份,增量备份及还原

案例&#xff1a;利用 xtrabackup 8.0 完全备份,增量备份及还原 MySQL8.0 在面对海量数据时&#xff0c;我们无法做到每天全量备份&#xff0c;因此 只能每周做一次全量备份。 而每天的话则进行增量备份&#xff0c;确保数据安全。 注意点&#xff1a;MySQL 8.0.26 版本对应需要…

基于Springboot的考编论坛网站的设计与实现(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的考编论坛网站的设计与实现&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层…