diff --git a/dao/src/main/java/cc/iotkit/dao/ProtocolComponentRepository.java b/dao/src/main/java/cc/iotkit/dao/ProtocolComponentRepository.java index 68d51cbb..2da53005 100755 --- a/dao/src/main/java/cc/iotkit/dao/ProtocolComponentRepository.java +++ b/dao/src/main/java/cc/iotkit/dao/ProtocolComponentRepository.java @@ -4,6 +4,11 @@ import cc.iotkit.model.protocol.ProtocolComponent; import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface ProtocolComponentRepository extends MongoRepository { + + List findByState(String state); + } diff --git a/dao/src/main/java/cc/iotkit/dao/ProtocolConverterRepository.java b/dao/src/main/java/cc/iotkit/dao/ProtocolConverterRepository.java old mode 100644 new mode 100755 diff --git a/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java b/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java index a5b63f50..005097ae 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java @@ -6,6 +6,7 @@ import cc.iotkit.common.utils.ReflectUtil; import cc.iotkit.comp.CompConfig; import cc.iotkit.comp.mqtt.MqttComponent; import cc.iotkit.comps.ComponentManager; +import cc.iotkit.comps.config.ComponentConfig; import cc.iotkit.converter.ScriptConverter; import cc.iotkit.dao.ProtocolComponentRepository; import cc.iotkit.dao.ProtocolConverterRepository; @@ -37,11 +38,8 @@ import java.util.UUID; @RequestMapping("/protocol") public class ProtocolController { - @Value("${component.dir:./data/components}") - private String componentDir; - - @Value("${converter.dir:./data/converters}") - private String converterDir; + @Autowired + private ComponentConfig componentConfig; @Autowired private ProtocolComponentRepository protocolComponentRepository; @@ -58,16 +56,6 @@ public class ProtocolController { @Autowired private ComponentManager componentManager; - private Path getComponentFilePath(String comId) { - return Paths.get(String.format("%s/%s", componentDir, comId)) - .toAbsolutePath().normalize(); - } - - private Path getConverterFilePath(String conId) { - return Paths.get(String.format("%s/%s", converterDir, conId)) - .toAbsolutePath().normalize(); - } - @PostMapping("/uploadJar") public String uploadJar(@RequestParam("file") MultipartFile file, String id) { if (file == null) { @@ -77,15 +65,11 @@ public class ProtocolController { String fileName = StringUtils.cleanPath(file.getOriginalFilename()); try { if (StringUtils.hasLength(id)) { - Optional optComponent = protocolComponentRepository.findById(id); - if (!optComponent.isPresent()) { - throw new BizException("the protocol component does not exists"); - } - dataOwnerService.checkOwner(optComponent.get()); + getAndCheckComponent(id); } else { id = UUID.randomUUID().toString(); } - Path jarFilePath = getComponentFilePath(id); + Path jarFilePath = componentConfig.getComponentFilePath(id); Files.createDirectories(jarFilePath); Path targetLocation = jarFilePath.resolve(fileName); Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING); @@ -101,7 +85,7 @@ public class ProtocolController { if (!StringUtils.hasLength(id)) { throw new BizException("component id is blank"); } - Path jarPath = getComponentFilePath(id); + Path jarPath = componentConfig.getComponentFilePath(id); if (!jarPath.resolve(component.getJarFile()).toFile().exists()) { throw new BizException("component jar file does not exist"); } @@ -125,20 +109,15 @@ public class ProtocolController { if (!StringUtils.hasLength(id)) { throw new BizException("component id is blank"); } - Path jarPath = getComponentFilePath(id); + Path jarPath = componentConfig.getComponentFilePath(id); if (!jarPath.resolve(component.getJarFile()).toFile().exists()) { throw new BizException("component jar file does not exist"); } - Optional optComponent = protocolComponentRepository.findById(component.getId()); - if (!optComponent.isPresent()) { - throw new BizException("the protocol component does not exists"); - } - - ProtocolComponent oldComponent = optComponent.get(); + ProtocolComponent oldComponent = getAndCheckComponent(id); component = ReflectUtil.copyNoNulls(component, oldComponent); - dataOwnerService.checkOwner(component); try { + componentManager.deRegister(id); protocolComponentRepository.save(component); } catch (Throwable e) { throw new BizException("add protocol component error", e); @@ -147,14 +126,9 @@ public class ProtocolController { @GetMapping("/getComponentScript/{id}") public String getComponentScript(@PathVariable("id") String id) { - Optional optComponent = protocolComponentRepository.findById(id); - if (!optComponent.isPresent()) { - throw new BizException("the component does not exists"); - } - ProtocolComponent component = optComponent.get(); - dataOwnerService.checkOwner(component); + getAndCheckComponent(id); try { - Path path = getComponentFilePath(id); + Path path = componentConfig.getComponentFilePath(id); File file = path.resolve(ProtocolComponent.SCRIPT_FILE_NAME).toFile(); return FileUtils.readFileToString(file, "UTF-8"); } catch (Throwable e) { @@ -167,28 +141,37 @@ public class ProtocolController { public void saveComponentScript( @PathVariable("id") String id, @RequestBody String script) { - Optional optComponent = protocolComponentRepository.findById(id); - if (!optComponent.isPresent()) { - throw new BizException("the component does not exists"); - } - ProtocolComponent oldComponent = optComponent.get(); - dataOwnerService.checkOwner(oldComponent); + ProtocolComponent oldComponent = getAndCheckComponent(id); try { - Path path = getComponentFilePath(id); + Path path = componentConfig.getComponentFilePath(id); File file = path.resolve(ProtocolComponent.SCRIPT_FILE_NAME).toFile(); script = JsonUtil.parse(script, String.class); FileUtils.writeStringToFile(file, script, "UTF-8", false); + + componentManager.deRegister(id); protocolComponentRepository.save(oldComponent); } catch (Throwable e) { throw new BizException("save protocol component script error", e); } } + private ProtocolComponent getAndCheckComponent(@PathVariable("id") String id) { + Optional optComponent = protocolComponentRepository.findById(id); + if (!optComponent.isPresent()) { + throw new BizException("the component does not exists"); + } + ProtocolComponent oldComponent = optComponent.get(); + dataOwnerService.checkOwner(oldComponent); + return oldComponent; + } + @PostMapping("/deleteComponent/{id}") public void deleteComponent(@PathVariable("id") String id) { - dataOwnerService.checkOwner(protocolComponentRepository, id); + ProtocolComponent component = getAndCheckComponent(id); try { - Path path = Paths.get(String.format("%s/%s", componentDir, id)) + componentManager.deRegister(id); + + Path path = Paths.get(String.format("%s/%s", componentConfig.getComponentDir(), id)) .toAbsolutePath().normalize(); File file = path.toFile(); try { @@ -200,7 +183,7 @@ public class ProtocolController { } catch (NoSuchFileException e) { log.warn("delete component script error", e); } - protocolComponentRepository.deleteById(id); + protocolComponentRepository.deleteById(component.getId()); } catch (Throwable e) { throw new BizException("delete protocol component error", e); } @@ -212,6 +195,8 @@ public class ProtocolController { @PathVariable("page") int page) { Page components = protocolComponentRepository.findAll( PageRequest.of(page - 1, size, Sort.by(Sort.Order.desc("createAt")))); + components.getContent().forEach(c -> c.setState(componentManager.isRunning(c.getId()) ? + ProtocolComponent.STATE_RUNNING : ProtocolComponent.STATE_STOPPED)); return new Paging<>(components.getTotalElements(), components.getContent()); } @@ -240,14 +225,8 @@ public class ProtocolController { @PostMapping("/saveConverter") public void saveConverter(ProtocolConverter converter) { - Optional optConverter = protocolConverterRepository.findById(converter.getId()); - if (!optConverter.isPresent()) { - throw new BizException("the protocol converter does not exists"); - } - - ProtocolConverter oldConverter = optConverter.get(); + ProtocolConverter oldConverter = getAndCheckConverter(converter.getId()); converter = ReflectUtil.copyNoNulls(converter, oldConverter); - dataOwnerService.checkOwner(converter); try { protocolConverterRepository.save(converter); } catch (Throwable e) { @@ -255,16 +234,22 @@ public class ProtocolController { } } - @GetMapping("/getConverterScript/{id}") - public String getConverterScript(@PathVariable("id") String id) { + private ProtocolConverter getAndCheckConverter(String id) { Optional optConverter = protocolConverterRepository.findById(id); if (!optConverter.isPresent()) { - throw new BizException("the converter does not exists"); + throw new BizException("the protocol converter does not exists"); } + ProtocolConverter converter = optConverter.get(); dataOwnerService.checkOwner(converter); + return converter; + } + + @GetMapping("/getConverterScript/{id}") + public String getConverterScript(@PathVariable("id") String id) { + getAndCheckConverter(id); try { - Path path = getConverterFilePath(id); + Path path = componentConfig.getConverterFilePath(id); File file = path.resolve(ProtocolConverter.SCRIPT_FILE_NAME).toFile(); return FileUtils.readFileToString(file, "UTF-8"); } catch (Throwable e) { @@ -277,14 +262,9 @@ public class ProtocolController { public void saveConverterScript( @PathVariable("id") String id, @RequestBody String script) { - Optional optConverter = protocolConverterRepository.findById(id); - if (!optConverter.isPresent()) { - throw new BizException("the converter does not exists"); - } - ProtocolConverter oldConverter = optConverter.get(); - dataOwnerService.checkOwner(oldConverter); + getAndCheckConverter(id); try { - Path path = getConverterFilePath(id); + Path path = componentConfig.getConverterFilePath(id); File file = path.resolve(ProtocolConverter.SCRIPT_FILE_NAME).toFile(); script = JsonUtil.parse(script, String.class); FileUtils.writeStringToFile(file, script, "UTF-8", false); @@ -295,9 +275,9 @@ public class ProtocolController { @PostMapping("/deleteConverter/{id}") public void deleteConverter(@PathVariable("id") String id) { - dataOwnerService.checkOwner(protocolConverterRepository, id); + getAndCheckConverter(id); try { - Path path = Paths.get(String.format("%s/%s", componentDir, id)) + Path path = Paths.get(String.format("%s/%s", componentConfig.getConverterDir(), id)) .toAbsolutePath().normalize(); File file = path.toFile(); try { @@ -315,28 +295,21 @@ public class ProtocolController { } } - @PostMapping("/component/{id}/{state}") - public void startComponent(@PathVariable("id") String id, - @PathVariable("state") String state) { - - } - - - @GetMapping("/registerMqtt") - public void registerMqtt() throws IOException { - MqttComponent component = new MqttComponent(); - component.create(new CompConfig(300, "{\"port\":2883,\"ssl\":false}")); - ScriptConverter converter = new ScriptConverter(); - converter.setScript(FileUtils.readFileToString(new File("/Users/sjg/home/gitee/open-source/converter.js"), "UTF-8")); - component.setConverter(converter); - componentManager.register("123", component); - componentManager.start("123", FileUtils.readFileToString(new File("/Users/sjg/home/gitee/open-source/component.js"), "UTF-8")); - } - - @GetMapping("/deregisterMqtt") - public void deregisterMqtt() { - componentManager.stop("123"); - componentManager.deRegister("123"); + @PostMapping("/component/{id}/state/{state}") + public void changeComponentState(@PathVariable("id") String id, + @PathVariable("state") String state) { + ProtocolComponent component = getAndCheckComponent(id); + String converterId = component.getConverter(); + getAndCheckConverter(converterId); + if (ProtocolComponent.STATE_RUNNING.equals(state)) { + componentManager.register(component); + componentManager.start(component.getId()); + component.setState(ProtocolComponent.STATE_RUNNING); + } else { + componentManager.deRegister(id); + component.setState(ProtocolComponent.STATE_STOPPED); + } + protocolComponentRepository.save(component); } } diff --git a/model/src/main/java/cc/iotkit/model/protocol/ProtocolConverter.java b/model/src/main/java/cc/iotkit/model/protocol/ProtocolConverter.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentClassLoader.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentClassLoader.java index f025f5d3..bd205160 100755 --- a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentClassLoader.java +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentClassLoader.java @@ -16,12 +16,12 @@ import java.nio.charset.Charset; @Slf4j public class ComponentClassLoader { - protected Class findClass(String name) throws ClassNotFoundException { + protected static Class findClass(String name) throws ClassNotFoundException { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); return (Class) classLoader.loadClass(name); } - private String addUrl(File jarPath) throws NoSuchMethodException, InvocationTargetException, + private static String addUrl(File jarPath) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException { URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader(); Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); @@ -35,9 +35,9 @@ public class ComponentClassLoader { return StreamUtils.copyToString(is, Charset.forName("UTF-8")); } - public IComponent getComponent(File jarPath) { + public static IComponent getComponent(File jarFile) { try { - String className = addUrl(jarPath); + String className = addUrl(jarFile); Class componentClass = findClass(className); return componentClass.newInstance(); } catch (Throwable e) { diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentManager.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentManager.java index 2a60e15b..7e27ceae 100755 --- a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentManager.java +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentManager.java @@ -3,18 +3,30 @@ package cc.iotkit.comps; import cc.iotkit.common.exception.BizException; import cc.iotkit.common.utils.JsonUtil; +import cc.iotkit.comp.CompConfig; import cc.iotkit.comp.IComponent; import cc.iotkit.comps.config.CacheKey; +import cc.iotkit.comps.config.ComponentConfig; import cc.iotkit.comps.service.DeviceBehaviourService; import cc.iotkit.converter.DeviceMessage; +import cc.iotkit.converter.ScriptConverter; import cc.iotkit.converter.ThingService; +import cc.iotkit.dao.ProtocolComponentRepository; import cc.iotkit.model.device.message.ThingModelMessage; +import cc.iotkit.model.protocol.ProtocolComponent; +import cc.iotkit.model.protocol.ProtocolConverter; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; +import javax.annotation.PostConstruct; +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -23,31 +35,84 @@ import java.util.concurrent.TimeUnit; public class ComponentManager { private final Map components = new HashMap<>(); + private final Map scripts = new HashMap<>(); + private final Map states = new HashMap<>(); @Autowired private DeviceBehaviourService deviceBehaviourService; @Autowired private StringRedisTemplate redisTemplate; + @Autowired + private ComponentConfig componentConfig; + @Autowired + private ProtocolComponentRepository componentRepository; - public void register(String id, IComponent component) { + @PostConstruct + public void init() { + List componentList = componentRepository.findByState(ProtocolComponent.STATE_RUNNING); + for (ProtocolComponent component : componentList) { + register(component); + start(component.getId()); + } + } + + public void register(ProtocolComponent component) { + String id = component.getId(); + if (components.containsKey(id)) { + return; + } + + Path path = componentConfig.getComponentFilePath(id); + File file = path.resolve(component.getJarFile()).toAbsolutePath().toFile(); + IComponent componentInstance = ComponentClassLoader.getComponent(file); + if (componentInstance == null) { + throw new BizException("instance component failed"); + } + componentInstance.create(new CompConfig(300, component.getConfig())); + + try { + ScriptConverter scriptConverter = new ScriptConverter(); + Path converterPath = componentConfig.getConverterFilePath(component.getConverter()); + String converterScript = FileUtils.readFileToString(converterPath. + resolve(ProtocolConverter.SCRIPT_FILE_NAME).toFile(), "UTF-8"); + + scriptConverter.setScript(converterScript); + componentInstance.setConverter(scriptConverter); + + String componentScript = FileUtils.readFileToString(path. + resolve(ProtocolComponent.SCRIPT_FILE_NAME).toFile(), "UTF-8"); + register(id, componentInstance, componentScript); + } catch (IOException e) { + throw new BizException("get component script error", e); + } + } + + public void register(String id, IComponent component, String script) { components.put(id, component); + scripts.put(id, script); + states.put(id, false); } public void deRegister(String id) { IComponent component = components.remove(id); + scripts.remove(id); + states.remove(id); + component.stop(); component.destroy(); } - public void start(String id, String script) { + public void start(String id) { IComponent component = components.get(id); if (component == null) { return; } + String script = scripts.get(id); component.setHandler( new MessageHandler(this, component, script, component.getConverter(), deviceBehaviourService)); component.start(); + states.put(id, true); } public void stop(String id) { @@ -56,6 +121,11 @@ public class ComponentManager { return; } component.stop(); + states.put(id, false); + } + + public boolean isRunning(String id) { + return states.containsKey(id) && states.get(id); } public void send(ThingService service) { diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/MessageHandler.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/MessageHandler.java index 1c61dec1..21aeec60 100755 --- a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/MessageHandler.java +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/MessageHandler.java @@ -48,12 +48,12 @@ public class MessageHandler implements IMessageHandler { this.component = component; this.converter = converter; this.deviceBehaviourService = deviceBehaviourService; - scriptObj = engine.eval(script); + scriptObj = engine.eval(String.format("new (function () {\n%s})()", script)); } public ReceiveResult onReceive(Map head, String type, String msg) { try { - ScriptObjectMirror result = (ScriptObjectMirror) engine.invokeMethod(scriptObj, "onReceive", head, type, msg); + ScriptObjectMirror result = (ScriptObjectMirror) invokeMethod("onReceive", head, type, msg); log.info("onReceive script result:{}", JsonUtil.toJsonString(result)); Object rstType = result.get("type"); if (rstType == null) { @@ -107,10 +107,10 @@ public class MessageHandler implements IMessageHandler { private void doRegister(RegisterInfo reg) throws ScriptException, NoSuchMethodException { try { deviceBehaviourService.register(reg); - engine.invokeMethod(scriptObj, "onRegistered", reg, "true"); } catch (Throwable e) { log.error("register error", e); - engine.invokeMethod(scriptObj, "onRegistered", reg, "false"); + } finally { + invokeMethod("onRegistered", reg, "false"); } } @@ -120,13 +120,20 @@ public class MessageHandler implements IMessageHandler { auth.getDeviceName(), auth.getProductSecret(), auth.getDeviceSecret()); - engine.invokeMethod(scriptObj, "onAuthed", auth, true); } catch (Throwable e) { log.error("device auth error", e); - engine.invokeMethod(scriptObj, "onAuthed", auth, false); + } finally { + invokeMethod("onAuthed", auth, "false"); } } + private Object invokeMethod(String name, Object... args) throws ScriptException, NoSuchMethodException { + if (((ScriptObjectMirror) scriptObj).get(name) != null) { + return engine.invokeMethod(scriptObj, name, args); + } + return null; + } + private void doStateChange(DeviceState state) { try { component.onDeviceStateChange(state); diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/config/ComponentConfig.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/config/ComponentConfig.java new file mode 100755 index 00000000..bb8d5db4 --- /dev/null +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/config/ComponentConfig.java @@ -0,0 +1,29 @@ +package cc.iotkit.comps.config; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +import java.nio.file.Path; +import java.nio.file.Paths; + +@Configuration +@Data +public class ComponentConfig { + + @Value("${component.dir:./data/components}") + private String componentDir; + + @Value("${converter.dir:./data/converters}") + private String converterDir; + + public Path getComponentFilePath(String comId) { + return Paths.get(componentDir, comId) + .toAbsolutePath().normalize(); + } + + public Path getConverterFilePath(String conId) { + return Paths.get(converterDir, conId) + .toAbsolutePath().normalize(); + } +} diff --git a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ScriptConverter.java b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ScriptConverter.java index 8e7ec8fd..0c56ba70 100755 --- a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ScriptConverter.java +++ b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ScriptConverter.java @@ -21,7 +21,7 @@ public class ScriptConverter implements IConverter { public void setScript(String script) { try { - scriptObj = engine.eval(script); + scriptObj = engine.eval(String.format("new (function () {\n%s})()", script)); } catch (ScriptException e) { log.error("eval converter script error", e); } diff --git a/protocol-gateway/emqx-component/dependency-reduced-pom.xml b/protocol-gateway/emqx-component/dependency-reduced-pom.xml old mode 100644 new mode 100755 diff --git a/protocol-gateway/mqtt-component/dependency-reduced-pom.xml b/protocol-gateway/mqtt-component/dependency-reduced-pom.xml old mode 100644 new mode 100755