Bonjour. Conseiller Yorozu Sugimon: miam:. Cette fois, je vais essayer de développer un composant (adaptateur) en utilisant le SDK de HULFT IoT Edge Streaming. Il est décrit de manière à être complété dans les trois parties.
Cette fois, comme deuxième étape, je développerai un plug en utilisant le SDK HULFT IoT EdgeStreaming Plugin. Il existe d'autres articles sur la configuration et l'exécution, veuillez donc les consulter.
: arrow_forward: [J'ai essayé de créer un plug-in avec HULFT IoT Edge Streaming Configuration] (https://qiita.com/sugimon/items/cf7503479c6e4c46c3b3) : arrow_forward: J'ai essayé de créer un plug-in avec HULFT IoT Edge Streaming Développement : arrow_forward: [J'ai essayé de créer un plug-in avec HULFT IoT Edge Streaming Execution](https://qiita.com/sugimon/items/93f47d7bd472a8b18e54)
La configuration pour créer un plug-in pour EdgeStreaming est la suivante.
Il s'agit de la partie Runtime qui exécute le processus de streaming spécifié par Studio.
SourceOperation `Ceci est une opération pour générer des données de streaming (Tuple). Ce sera le "traitement d'entrée".
SinkOperation `Il s'agit d'une opération de sortie des données Streaming (Tuple) vers l'extérieur. Cela devient "traitement de sortie". ''
UDSFOperation
Il s'agit d'une opération de conversion de données Streaming (Tuple). Il génère également le Streming converti (Tuple). "Traitement d'entrée / sortie (conversion)"
Génère un BQL (syntaxe de type SQL) qui indique à RunTime comment effectuer le traitement en continu.
AdapterModuleComponent ʻUne classe qui représente un composant (adaptateur). C'est plusieurs-à-un avec l'opération. ''
BQLPluginSourceOperationFactory `Définit les propriétés de SourceOperartion. "Traitement des entrées" Sort le BQL (instruction Create Source) qui crée l'opération Source. ''
BQLPluginOutputOperationFactory `Définit les propriétés de SinkOperation. "Traitement de sortie" Produit une instruction BQL (Create Sink) qui crée une opération Sink. ''
BQLPluginUDSFOperationFactory ʻDéfinir les propriétés UDSF. "Traitement d'entrée / sortie (conversion)" Sort une instruction BQL (instruction Select) qui génère une opération UDSF. ''
Cette fois, j'ai essayé de créer un plug-in sous la forme suivante.
·Informations de base
** ・ Informations sur le fonctionnement **
Implémente le processus de streaming spécifié par Studio.
** Préparation environnementale **
$ SDK_HOME / dev / go / src / github.sis.saison.co.jp / sherpa / es-agent / sample
$ SDK_HOME / dev / go / src / github.sis.saison.co.jp / sherpa / es-agent / sample / plugin
$ SDK_HOME / dev / go / src / github.sis.saison.co.jp / sherpa / es-agent / sample / external
** Création d'un fichier source ** Créons un fichier source avec le nom de fichier suivant dans le répertoire du module (exemple dans ce cas).
-La structure du fichier est la suivante.
├─sample
│ ├─source.go (traitement d'entrée)
│ ├─sink.go (traitement de sortie)
│ ├─udsf.go (traitement de conversion entrée / sortie)
│ │
│ ├─external
│ │ ├─plugin_main.aller (fonction principale)
│ │ │
│ └─plugin
│ │ ├─plugin.go (enregistrez les fichiers source sous chaque échantillon)
│ │ │
Créons maintenant le fichier source.
** ・ source.go (traitement d'entrée) ** Créez un processus pour générer des nombres pseudo aléatoires à intervalles de temps réguliers. Le flux principal est le suivant.
Tuple
{
"type": "object",
"required": ["payload"],
"properties": {
"payload": {
"type": "object",
"required": ["value"],
"properties": {
"value": {
"type": "number"
}
}
}
}
}
Les données Tuple JSON de sortie ont le format suivant.
{"payload": {"value": 3.5423242}}
J'ai créé source.go comme suit.
source.go
package sample
import (
"math/rand"
"time"
"gopkg.in/sensorbee/sensorbee.v0/bql"
"gopkg.in/sensorbee/sensorbee.v0/core"
"gopkg.in/sensorbee/sensorbee.v0/data"
)
type source struct {
interval time.Duration
term chan struct{}
}
func (s *source) GenerateStream(ctx *core.Context, w core.Writer) error {
rand.Seed(time.Now().UnixNano())
next := time.Now()
for {
val := rand.Float64()
m := data.Map{"value": data.Float(val)}
t := core.NewTuple(data.Map{"payload": m})
if s.interval > 0 {
t.Timestamp = next
}
ctx.Log().Debug("generation: ", val)
if err := w.Write(ctx, t); err != nil {
return err
}
if s.interval > 0 {
now := time.Now()
next = next.Add(s.interval)
if next.Before(now) {
next = now.Add(s.interval)
}
select {
case <-s.term:
return core.ErrSourceStopped
case <-time.After(next.Sub(now)):
}
}
}
return nil
}
func (s *source) Stop(ctx *core.Context) error {
s.term <- struct{}{}
return nil
}
func CreateSource(ctx *core.Context, ioParams *bql.IOParams, params data.Map) (core.Source, error) {
interval, err := getInterval(params)
if err != nil {
return nil, err
}
return &source{
interval: interval,
term: make(chan struct{}),
}, nil
}
func getInterval(params data.Map) (time.Duration, error) {
interval := 1 * time.Second
if v, ok := params["interval"]; ok {
i, err := data.ToDuration(v)
if err != nil {
return interval, err
}
interval = i
}
return interval, nil
}
** ・ sink.go (traitement de sortie) ** Créez un processus pour tronquer par le nombre de chiffres décimaux effectifs et sortir dans le journal.
Le flux principal est le suivant.
Tuple
{
"type": "object",
"required": ["payload"],
"properties": {
"payload": {
"type": "object",
"required": ["value", "formula"],
"properties": {
"value": {
"type": "number"
}
"formula": {
"type": "string"
}
}
}
}
}
J'ai créé sink.go comme suit.
sink.go
package sample
import (
"fmt"
"math"
"gopkg.in/sensorbee/sensorbee.v0/bql"
"gopkg.in/sensorbee/sensorbee.v0/core"
"gopkg.in/sensorbee/sensorbee.v0/data"
)
type sink struct {
decimal int
}
func (s *sink) Write(ctx *core.Context, tuple *core.Tuple) error {
p, ok := tuple.Data["payload"]
if !ok {
return fmt.Errorf("the tuple doesn't have the required field: payload")
}
payload, err := data.AsMap(p)
if err != nil {
return err
}
v, ok := payload["value"]
if !ok {
return fmt.Errorf("the tuple doesn't have the required field: value")
}
value, err := data.AsFloat(v)
if err != nil {
return err
}
f, ok := payload["formula"]
if !ok {
return fmt.Errorf("the tuple doesn't have the required field: formula")
}
formula, err := data.AsString(f)
if err != nil {
return err
}
shift := math.Pow(10, float64(s.decimal))
value = math.Floor(value*shift) / shift
ctx.Log().Infof("formula: %s", formula)
ctx.Log().Infof("value: %f", value)
return nil
}
func (s *sink) Close(ctx *core.Context) error {
return nil
}
func CreateSink(ctx *core.Context, ioParams *bql.IOParams, params data.Map) (core.Sink, error) {
decimal, err := getDecimal(params)
if err != nil {
return nil, err
}
return &sink{
decimal: decimal,
}, nil
}
func getDecimal(params data.Map) (int, error) {
node, ok := params["decimal"]
if !ok {
return 0, fmt.Errorf("decimal is required")
}
decimal, err := data.AsInt(node)
if err != nil {
return 0, fmt.Errorf("decimal must be a int:%s", err)
}
return int(decimal), nil
}
** ・ udsf.go (traitement de conversion d'entrée / sortie) ** L'objet udsf reçoit les données suivantes:
L'objet udsf continue de calculer la valeur de l'élément de valeur Tuple reçu avec l'opérateur spécifié dans la valeur actuelle (valeur_initial au début).
J'ai créé udsf.go comme suit.
udsf.go
package sample
import (
"fmt"
"gopkg.in/sensorbee/sensorbee.v0/bql/udf"
"gopkg.in/sensorbee/sensorbee.v0/core"
"gopkg.in/sensorbee/sensorbee.v0/data"
)
type operator byte
const (
none = ' '
plus = '+'
minus = '-'
times = '*'
divided = '/'
)
type udsf struct {
cur float64
ope operator
}
func (u *udsf) Process(ctx *core.Context, tuple *core.Tuple, w core.Writer) error {
p, ok := tuple.Data["payload"]
if !ok {
return fmt.Errorf("the tuple doesn't have the required field: payload")
}
payload, err := data.AsMap(p)
if err != nil {
return err
}
v, ok := payload["value"]
if !ok {
return fmt.Errorf("the tuple doesn't have the required field: value")
}
value, err := data.AsFloat(v)
if err != nil {
return err
}
var formula string
newVal := u.cur
switch u.ope {
case plus:
newVal += value
case minus:
newVal -= value
case times:
newVal *= value
case divided:
newVal /= value
}
formula = fmt.Sprintf("%f %s %f", u.cur, string(u.ope), value)
ctx.Log().Debug("calculate: " + formula)
m := data.Map{
"value": data.Float(newVal),
"formula": data.String(formula),
}
if err := w.Write(ctx, core.NewTuple(data.Map{"payload": m})); err != nil {
return err
}
u.cur = newVal
return nil
}
func (u *udsf) Terminate(ctx *core.Context) error {
return nil
}
func CreateUDSF(decl udf.UDSFDeclarer, params data.Map) (udf.UDSF, error) {
inputStream, err := getStreamName(params)
if err != nil {
return nil, err
}
operator, err := getOperator(params)
if err != nil {
return nil, err
}
initialValue, err := getInitialValue(params)
if err != nil {
return nil, err
}
if err := decl.Input(inputStream, nil); err != nil {
return nil, err
}
return &udsf{
ope: operator,
cur: initialValue,
}, nil
}
func getStreamName(params data.Map) (string, error) {
node, ok := params["stream_name"]
if !ok {
return "", fmt.Errorf("stream_name is required")
}
streamName, err := data.AsString(node)
if err != nil {
return "", fmt.Errorf("stream_name must be a string:%s", err)
}
return streamName, nil
}
func getOperator(params data.Map) (operator, error) {
node, ok := params["operator"]
if !ok {
return none, fmt.Errorf("operator is required")
}
operatorStr, err := data.AsString(node)
if err != nil {
return none, fmt.Errorf("operator must be a string:%s", err)
}
switch operatorStr {
case "plus":
return plus, nil
case "minus":
return minus, nil
case "times":
return times, nil
case "divided":
return divided, nil
default:
return none, fmt.Errorf("invalid oparator")
}
}
func getInitialValue(params data.Map) (float64, error) {
initialValue := 0.0
node, ok := params["initial_value"]
if !ok {
return initialValue, nil
}
initialValue, err := data.AsFloat(node)
if err != nil {
return initialValue, fmt.Errorf("initial_value is invalid")
}
return initialValue, nil
}
** Enregistrement du fichier source ** Créez plugin.go dans le répertoire plugin et implémentez le processus d'enregistrement pour les opérations Source, Sink et UDSF (à utiliser comme BQL).
J'ai créé plugin.go comme suit.
plugin.go
package plugin
import (
"github.sis.saison.co.jp/sherpa/es-agent/sample"
"gopkg.in/sensorbee/sensorbee.v0/bql"
"gopkg.in/sensorbee/sensorbee.v0/bql/udf"
)
func init() {
bql.MustRegisterGlobalSourceCreator("sample_source", bql.SourceCreatorFunc(sample.CreateSource))
bql.MustRegisterGlobalSinkCreator("sample_sink", bql.SinkCreatorFunc(sample.CreateSink))
udf.MustRegisterGlobalUDSFCreator("sample_udsf", udf.MustConvertToUDSFCreator(sample.CreateUDSF))
}
** Création de la fonction principale ** Enfin, créez et implémentez plugin_main.go dans le répertoire externe de la fonction main qui appelle le processus en tant que module d'exécution unique.
J'ai créé plugin_main.go comme suit.
plugin_main.go
package main
import (
"os"
"github.sis.saison.co.jp/sherpa/es-agent/external/plugin"
_ "github.sis.saison.co.jp/sherpa/es-agent/sample/plugin"
)
func main() {
if err := plugin.NewServer().ListenAndServe(); err != nil {
os.Exit(1)
}
}
À ce stade, la préparation côté Runtime est terminée. Ensuite, nous implémenterons le côté environnement de développement.
Implémente la génération BQL (syntaxe de type SQL) qui indique à Runtime comment effectuer le traitement de streaming.
** Préparation environnementale **
** Création d'un répertoire de modules **
-Créez le répertoire $ SDK_HOME / dev / sample_adapter
.
** Copier un fichier **
-Copiez build.xml et config.properties dans le répertoire $ SDK_HOME / dev / conf
dans le répertoire du module.
$SDK_HOME/dev/conf/build.xml
⇒ $SDK_HOME/dev/sample_adapter/build.xml
$SDK_HOME/dev/conf/config.properties
⇒ $SDK_HOME/dev/sample_adapter/config.propertites
Modifiez le fichier config.properties copié.
Implementation-Title=SampleAdapter
Implementation-Vendor=sugimon
Implementation-Version=0
module.category=Sample
module.label=Sample Plugin
display.name=Sample Plugin Adapter
plugin.name=sample_plugin
esagent.plugin.package=github.sis.saison.co.jp/sherpa/es-agent/sample
** Créer un répertoire pour les fichiers source **
Créez un répertoire src dans $ SDK_HOME / dev / sample_adapter
.
($SDK_HOME/dev/sample_adapter/src)
Ensuite, créez le package de fichiers java com / appresso / ds / dp / modules / adapter / sample
Créez un répertoire pour les packages suivants afin que
($SDK_HOME/dev/sample_adapter/src/com/appresso/ds/dp/modules/adapter/sample)
** Création d'un fichier source ** Créez un fichier source dans le répertoire du package avec le nom de fichier suivant.
・SampleAdapterModuleComponent.java ・SampleSinkOperationFactory.java ・SampleSourceOperationFactory.java ・SampleUDSFOperationFactory.java
├─ sample_adapter
│ │ build.xml
│ │ config.properties
│ ├─ src
│ │ └com
│ │ └appresso
│ │ └ds
│ │ └dp
│ │ └modules
│ │ └adapter
│ │ └sample
│ │ SampleAdapterModuleComponent.java
│ │ SampleSinkOperationFactory.java
│ │ SampleSourceOperationFactory.java
│ │ SampleUDSFOperationFactory.java
Créons également un fichier source pour chacun d'entre eux.
** ・ SampleSourceOperationFactory.java (traitement d'entrée) ** Renvoie un objet contenant les propriétés de l'opération Source ou un objet d'opération. (Classe source d'héritage: classe BQLPluginSourceOperationFactory)
J'ai créé SampleSourceOperationFactory.java comme suit.
SampleSourceOperationFactory.java
package com.appresso.ds.dp.modules.adapter.sample;
import com.appresso.ds.common.spi.constraint.NumberFillin;
import com.appresso.ds.common.spi.param.SimpleParameter;
import com.appresso.ds.common.xmlfw.xml.XmlHandler;
import com.appresso.ds.dp.share.adapter.bql.common.BQLPluginSourceOperationFactory;
import com.appresso.ds.dp.spi.OperationConfiguration;
import com.appresso.ds.dp.spi.OperationConfigurator;
import org.xml.sax.SAXException;
import static com.appresso.ds.common.bql.BQLSimpleParameterType.FLOAT;
public class SampleSourceOperationFactory extends BQLPluginSourceOperationFactory {
@Override
protected String getLabel() {
return "Sample source";
}
@Override
protected String getPluginName() {
return "sample_plugin";
}
@Override
public String getOperationName() {
return "sample_source";
}
@Override
protected String getTypeName() {
return "sample_source";
}
@Override
protected void setupOperationConfigurator(OperationConfigurator operationConfigurator) {
operationConfigurator.addSimpleParameter(createIntervalParameter());
}
@Override
protected void setupOutputSchema(XmlHandler handler, OperationConfiguration conf) throws Exception {
handler.startElement("", "payload", "payload", EMPTY_ATTRIBUTE);
writeElement(handler, "value");
handler.endElement("", "payload", "payload");
}
protected void writeElement(XmlHandler handler, String name) throws SAXException {
handler.startElement("", name, name, EMPTY_ATTRIBUTE);
handler.endElement("", name, name);
}
static SimpleParameter createIntervalParameter() {
NumberFillin fillin = new NumberFillin();
fillin.setMinValue(0.001);
fillin.setMaxValue(1314000);
fillin.setAllowMin(true);
fillin.setAllowMax(true);
fillin.setPrecision(10);
fillin.setDecimal(3);
fillin.setAllowDouble(true);
fillin.setLabel("Interval[sec]");
fillin.setRequired(true);
return new SimpleParameter(FLOAT.toParameterKey("interval"), fillin);
}
}
** ・ SampleSinkOperationFactory.java (traitement de sortie) ** Renvoie un objet contenant les propriétés d'une opération Sink ou d'un objet d'opération. (Classe source d'héritage: classe BQLPluginSinkOperationFactory)
J'ai créé SampleSinkOperationFactory.java comme suit.
SampleSinkOperationFactory.java
package com.appresso.ds.dp.modules.adapter.sample;
import com.appresso.ds.common.spi.constraint.NumberFillin;
import com.appresso.ds.common.spi.param.SimpleParameter;
import com.appresso.ds.common.xmlfw.xml.XmlHandler;
import com.appresso.ds.dp.share.adapter.bql.common.BQLPluginOutputOperationFactory;
import com.appresso.ds.dp.spi.OperationConfiguration;
import com.appresso.ds.dp.spi.OperationConfigurator;
import com.appresso.ds.dp.spi.OperationContext;
import org.xml.sax.SAXException;
import static com.appresso.ds.common.bql.BQLSimpleParameterType.INTEGER;
public class SampleSinkOperationFactory extends BQLPluginOutputOperationFactory {
@Override
protected String getLabel() {
return "Sample sink";
}
@Override
protected String getPluginName() {
return "sample_plugin";
}
@Override
public String getOperationName() {
return "sample_sink";
}
@Override
protected String getTypeName() {
return "sample_sink";
}
@Override
protected void setupOperationConfigurator(OperationConfigurator operationConfigurator) {
operationConfigurator.addSimpleParameter(createDecimalParameter());
}
protected void setupInputSchema(XmlHandler handler, OperationConfiguration conf, OperationContext context)
throws Exception {
handler.startElement("", "payload", "payload", EMPTY_ATTRIBUTE);
writeElement(handler, "formula");
writeElement(handler, "value");
handler.endElement("", "payload", "payload");
}
protected void writeElement(XmlHandler handler, String name) throws SAXException {
handler.startElement("", name, name, EMPTY_ATTRIBUTE);
handler.endElement("", name, name);
}
static SimpleParameter createDecimalParameter() {
NumberFillin fillin = new NumberFillin();
fillin.setMinValue(0);
fillin.setMaxValue(10);
fillin.setAllowMin(true);
fillin.setAllowMax(true);
fillin.setLabel("Decimal");
fillin.setRequired(true);
return new SimpleParameter(INTEGER.toParameterKey("decimal"), fillin);
}
}
** ・ ExempleUDSFOperationFactory ** Renvoie un objet contenant les propriétés d'une opération UDSF ou d'un objet d'opération.
J'ai créé SampleUDSFOperationFactory.java comme suit.
SampleUDSFOperationFactory.java
package com.appresso.ds.dp.modules.adapter.sample;
import com.appresso.ds.common.bql.UDSFFromArgument;
import com.appresso.ds.common.bql.UDSFFromTemplate;
import com.appresso.ds.common.spi.constraint.Item;
import com.appresso.ds.common.spi.constraint.Multi;
import com.appresso.ds.common.spi.constraint.NumberFillin;
import com.appresso.ds.common.spi.param.SimpleParameter;
import com.appresso.ds.common.xmlfw.xml.XmlHandler;
import com.appresso.ds.dp.share.adapter.bql.common.BQLPluginUDSFOperationFactory;
import com.appresso.ds.dp.spi.OperationConfiguration;
import com.appresso.ds.dp.spi.OperationConfigurator;
import com.appresso.ds.dp.spi.OperationContext;
import org.xml.sax.SAXException;
import java.util.stream.Stream;
import static com.appresso.ds.common.bql.BQLSimpleParameterType.FLOAT;
import static com.appresso.ds.common.bql.BQLSimpleParameterType.STRING;
public class SampleUDSFOperationFactory extends BQLPluginUDSFOperationFactory {
@Override
protected String getLabel() {
return "Sample UDSF";
}
@Override
public String getPluginName() {
return "sample_plugin";
}
@Override
protected String getTypeName() {
return "sample_udsf";
}
@Override
public String getOperationName() {
return "sample_udsf";
}
@Override
protected void addArgs(UDSFFromTemplate template) {
template.addArg(new UDSFFromArgument(STRING.toParameterKey("operator")));
template.addArg(new UDSFFromArgument(FLOAT.toParameterKey("initial_value")));
}
@Override
protected void setupOperationConfigurator(OperationConfigurator operationConfigurator) {
setStreamConfigurationParameter(operationConfigurator);
operationConfigurator.addSimpleParameter(createOperatorParameter());
operationConfigurator.addSimpleParameter(createInitialValueParameter());
}
@Override
protected void setupInputSchema(XmlHandler handler, OperationConfiguration conf, OperationContext context)
throws Exception {
handler.startElement("", "payload", "payload", EMPTY_ATTRIBUTE);
writeElement(handler, "value");
handler.endElement("", "payload", "payload");
}
@Override
protected void setupOutputSchema(XmlHandler handler, OperationConfiguration conf, OperationContext context)
throws Exception {
handler.startElement("", "payload", "payload", EMPTY_ATTRIBUTE);
writeElement(handler, "formula");
writeElement(handler, "value");
handler.endElement("", "payload", "payload");
}
protected void writeElement(XmlHandler handler, String name) throws SAXException {
handler.startElement("", name, name, EMPTY_ATTRIBUTE);
handler.endElement("", name, name);
}
static SimpleParameter createInitialValueParameter() {
NumberFillin fillin = new NumberFillin();
fillin.setPrecision(10);
fillin.setDecimal(3);
fillin.setAllowDouble(true);
fillin.setLabel("Initial value");
fillin.setRequired(true);
return new SimpleParameter(FLOAT.toParameterKey("initial_value"), fillin);
}
static SimpleParameter createOperatorParameter(){
Multi multi = new Multi(Operator.getItems());
multi.setLabel("Operator");
multi.setRequired(true);
SimpleParameter param = new SimpleParameter(STRING.toParameterKey("operator"), multi);
return param;
}
enum Operator {
Plus("+","plus"),
Minus("-","minus"),
Times("*","times"),
Divided("/","divided");
public String getDisplayName() {
return displayName;
}
public String getValue() {
return value;
}
private final String displayName;
private final String value;
private Operator(String displayName, String value) {
this.displayName = displayName;
this.value=value;
}
Item toItem(){
return new Item(value,displayName);
}
static Item[] getItems(){
return Stream.of(Operator.values()).map(s->s.toItem()).toArray(Item[]::new);
}
}
}
** ・ SampleAdapterModuleComponent ** Une classe qui représente un composant (adaptateur).
J'ai créé SampleAdapterModuleComponent.java comme suit.
SampleAdapterModuleComponent.java
package com.appresso.ds.dp.modules.adapter.sample;
import java.util.ArrayList;
import java.util.List;
import com.appresso.ds.common.kernel.modules.LicenseManager;
import com.appresso.ds.common.license.LicensePackageType;
import com.appresso.ds.dp.spi.AdapterModuleComponent;
import com.appresso.ds.dp.spi.OperationFactory;
import com.appresso.ds.dp.spi.ResourceFactory;
public class SampleAdapterModuleComponent extends AdapterModuleComponent {
private static final String MODULE_COMPONENT_NAME = "Sample Adapter";
@Override
public OperationFactory[] getOperationFactories() throws Exception {
List<OperationFactory> operationFactories = new ArrayList<>();
operationFactories.add(new SampleSourceOperationFactory());
operationFactories.add(new SampleUDSFOperationFactory());
operationFactories.add(new SampleSinkOperationFactory());
return operationFactories.toArray(new OperationFactory[operationFactories.size()]);
}
@Override
public ResourceFactory[] getResourceFactories() throws Exception {
return new ResourceFactory[]{};
}
public void checkLicense() throws Exception {
LicenseManager licenseManager = getContext().getProxy(LicenseManager.class);
licenseManager.checkLicense(getModuleComponentName(), getPermittedPackageType());
}
private String getModuleComponentName() {
return MODULE_COMPONENT_NAME;
}
private int[] getPermittedPackageType() {
return new int[]{LicensePackageType.TYPE_BASIC_SERVER};
}
}
Cette fois, j'ai mis en œuvre le traitement séparément pour le côté environnement d'exécution et le côté environnement de développement. Ceci termine le processus de création du plug-in. La prochaine fois, j'aimerais les construire et les exécuter.
Dans ce blog, je voudrais continuer à présenter le contenu des consultations au "Yorozu Consultation Counter" de la technologie et les astuces qui sont nées.
Veuillez continuer à le vérifier et nous suivre si vous le souhaitez.
À la prochaine!