메뉴 닫기

1.2.3. 서비스 엔진

아파치 OFBiz는 서비스 지향 아키텍처(SOA)를 중심으로 특별히 설계되었습니다. 서비스는 입력 값 집합을 취하고 출력 값 집합을 생성하는 비즈니스 논리 단위입니다.

서비스는 프로그래밍 언어와 독립적입니다. 서비스가 기본 기술에서 벗어난 추상화이기 때문에 Java, 그루비, Jython 또는 다른 서비스를 사용하여 서비스가 구현되는지 여부는 중요하지 않습니다. 이렇게 하면 서로 다른 언어 간의 상호 운용성에 대해 걱정하지 않고 비즈니스 논리를 설계할 수 있는 최대의 유연성을 제공합니다.

소개

서비스는 함께 배치될 때 다양한 유형의 비즈니스 요구 사항을 처리하는 독립적인 논리 조각입니다. 서비스는 Workflow, Rules, Java, SOAP, Groovy 등 다양한 유형이 될 수 있습니다. Java 유형의 서비스는 정적 메서드인 이벤트와 매우 유사하지만 Services Framework에서는 웹 기반으로 제한하지 않습니다. 응용 프로그램. 서비스는 입력 매개변수가 맵에 있어야 하며 결과도 맵에 반환됩니다. 이것은 Map이 직렬화되고 저장되거나 HTTP(SOAP)를 통해 전달될 수 있기 때문에 좋습니다.

서비스는 서비스 정의를 통해 정의되며 특정 서비스 엔진에 할당됩니다. 각 서비스 엔진은 정의된 서비스를 적절한 방식으로 호출할 책임이 있습니다. 서비스는 웹 기반 애플리케이션에 연결되어 있지 않기 때문에 사용 가능한 응답 개체가 없을 때 서비스를 실행할 수 있습니다. 이를 통해 작업 스케줄러를 통해 백그라운드에서 실행되도록 서비스가 특정 시간에 실행되도록 예약할 수 있습니다.

서비스에는 다른 서비스를 호출할 수 있는 기능이 있습니다. 따라서 더 큰 작업을 수행하기 위해 작은 서비스를 함께 연결하면 기존 서비스를 훨씬 쉽게 재사용할 수 있습니다.

컴포넌트(ofbiz-component.xml 파일의 service-resource)에 선언된 서비스는 OFBiz 내 어디에서나, 내보내기 기능을 사용하여 외부에서도 도달할 수 있습니다. 이 가능성이 일반적으로 사용되지는 않지만(OOTB의 예는 없음) 애플리케이션에 특정한 서비스를 생성하는 것도 가능합니다. 해당 애플리케이션에서만 사용할 수 있도록 제한됩니다. 이를 위해 서비스 정의 및 구현 파일을 WEB-INF 디렉터리에 넣습니다. 배포 컨텍스트에서 동일한 이름을 사용하여 서비스를 재정의할 수도 있습니다(첫 번째 프레임워크, 테마, 응용 프로그램, 특수 목적, 핫 배포). 이것은 편리하지만 원하지 않는 경우 조심하십시오 …

웹 응용 프로그램에서 사용되는 경우 웹 이벤트에 서비스를 사용할 수 있으므로 이벤트를 작게 유지하고 Services Framework에서 기존 논리를 재사용할 수 있습니다. 또한 서비스는 외부 당사자가 액세스할 수 있는 ‘수출 가능’으로 정의할 수 있습니다. 현재 SOAP를 통해 서비스를 사용할 수 있도록 하는 SOAP EventHandler가 있습니다. 미래에 다른 형태의 원격 호출이 프레임워크에 추가될 수 있습니다.

서비스 디스패처

서비스 디스패처는 서비스가 호출되는 적절한 서비스 엔진으로 서비스 디스패치를 ​​처리합니다. 각 Entity Delegator에 대해 정확히 하나의 ServiceDispatcher가 있습니다. 애플리케이션에 여러 위임자가 있는 경우 여러 디스패처도 있습니다. ServiceDispatcher는 LocalDispatcher를 통해 액세스됩니다. ServiceDispatcher와 연결된 많은 LocalDispatcher가 있을 수 있습니다. 각 LocalDispatcher는 고유한 이름이 지정되며 고유한 서비스 정의 목록을 포함합니다. LocalDispatcher의 인스턴스를 생성할 때 DispatchContext도 생성되어 ServiceEngine에 전달됩니다.

LocalDispatcher는 응용 프로그램과 연결됩니다. 응용 프로그램은 ServiceDispatcher와 직접 통신하지 않습니다. LocalDispatcher에는 ServiceDispather를 통해 라우팅되는 서비스를 호출하기 위한 API가 포함되어 있습니다. 그러나 응용 프로그램은 실제 ServiceDispatcher와 다른 스레드에서 실행될 수 있으므로 무엇보다도 응용 프로그램 클래스 로더에 대한 참조를 유지하는 DispatchContext를 유지하는 것은 LocalDispatcher에 맡겨집니다.

디스패치 컨텍스트

DispatchContext는 인스턴스화 시 LocalDispatcher에 의해 생성됩니다. 이것은 런타임 디스패처 컨텍스트입니다. 각 Dispatcher에 대한 서비스를 처리하는 데 필요한 정보가 포함되어 있습니다. 이 컨텍스트에는 각 서비스 정의 파일에 대한 참조, 호출에 사용해야 하는 클래스 로더, 위임자에 대한 참조 및 사용자 정의 속성의 ‘백’과 함께 해당 디스패처가 포함됩니다. 이 컨텍스트는 호출될 때 각 서비스에 전달되고 디스패처에서 서비스 모델을 결정하는 데 사용됩니다.

서비스 엔진

서비스가 실제로 호출되는 곳입니다. 각 서비스에는 해당 정의에 할당된 엔진 이름이 있습니다. 이 엔진 이름은 serviceengine.xml 파일을 통해 매핑되고 호출될 때 GenericEngineFactory에 의해 인스턴스화됩니다. 타사 엔진이 지원되며 구현 시 GenericEngine 인터페이스를 따라야 합니다. 엔진 정의에 대한 자세한 내용은 서비스 엔진 구성 안내서 를 참조하십시오.

동기 및 비동기 서비스의 호출을 모두 처리하는 것은 엔진의 작업입니다. 비동기 서비스를 위해 작업 스케줄러를 사용하는 엔진은 GenericAsyncEngine을 확장할 수 있습니다.

작업 스케줄러

정밀한 작업 스케줄러가 이제 서비스 프레임워크와 통합되었습니다. 이것은 스케줄러에 가장 적합한 장소입니다. 작업을 실행할 준비가 되었을 때 HttpServletRequest 및 HttpServletResponse 개체를 사용할 수 있다고 보장할 수 없으므로 웹 컨트롤러와 통합하는 것은 의미가 없습니다. 또한 이 기능은 웹 환경에 국한되지 않을 때 가장 유용합니다.

스케줄러는 작업 관리/스케줄링에 사용되는 단일 스레드와 각 서비스 호출에 사용되는 별도의 스레드가 있는 다중 스레드 구성 요소입니다. 작업이 실행되도록 예약되면 스케줄러는 작업과 연결된 서비스 디스패처를 호출하여 자체 스레드에서 서비스를 호출합니다. 이렇게 하면 오래 걸리거나 시간이 많이 걸리는 작업이 대기열에 있는 다른 작업의 속도를 늦추는 것을 방지할 수 있습니다.

스케줄러는 이제 반복을 위한 iCalendar 규칙 구조를 지원합니다. 작업은 더 이상 XML 파일에 저장되지 않으며 각각은 ServiceDispatcher의 일부입니다. 각 ServiceDispatcher에 대해 하나의 작업 스케줄러가 있습니다(즉, GenericDelegator당 하나만 있음).

작동 방식:

스케줄러의 가장 좋은 사용 예는 비동기 서비스 호출입니다. 비동기 서비스가 호출되면 실행을 위해 큐에 대기할 작업 스케줄러로 전달됩니다. 되풀이 항목이 생성되고(RecurrenceInfo 및 RecurrenceRule 엔터티가 생성됨), 작업이 저장되고(JobSandbox 엔터티가 생성됨) 컨텍스트(Map)가 직렬화되어 저장됩니다(RuntimeData 엔터티가 생성됨). 그런 다음 스케줄러는 예약된 작업 목록의 맨 위에 작업을 추가하고(비동기 서비스에는 지연 시간이 없음) 호출됩니다.

작업은 더 이상 XML 파일에 정의되지 않습니다. JobSandbox 엔터티로 이동되었습니다. 대기열에 미리 정의된 작업을 추가할 계획인 웹 기반 클라이언트가 있지만 현재는 엔터티를 직접 만들어야 합니다.

서비스 정의

서비스는 서비스 정의 파일에 정의되어 있습니다. 모든 서비스 디스패처에 사용되는 전역 정의 파일과 단일 디스패처에만 연결된 개별 파일이 있습니다. LocalDispatcher가 생성되면 이러한 정의 파일을 가리키는 Arils 컬렉션이 전달됩니다. 이러한 파일은 XML을 사용하여 구성되며 서비스를 호출하는 데 필요한 정보를 정의합니다. 이 파일의 XSD는 여기 에서 찾을 수 있습니다 .

서비스는 특정 서비스 엔진과 연관된 고유한 이름으로 정의되며 입력 및 출력 매개변수는 명시적으로 정의됩니다. 다음은 서비스 정의의 예입니다.

<service name="userLogin" engine="java" location="org.ofbiz.commonapp.security.login.LoginServices" invoke="userLogin">
    <description>Authenticate a username/password; create a UserLogin object</description>
    <attribute name="login.username" type="String" mode="IN"/>
    <attribute name="login.password" type="String" mode="IN"/>
    <attribute name="userLogin" type="org.ofbiz.entity.GenericValue" mode="OUT" optional="true"/>
</service>

SERVICE ELEMENT

AttributeRequired?DescriptionDefault Value
nameYThe unique name of the service.
engineYThe name of the engine (defined in serviceengine.xml).
locationNThe location or package of the service’s class.
invokeNThe method name of the service.
authNDoes this service require authorization? (true/false)true
debugNEnable verbose debugging when calling this service?true
default-entity-nameNThe default Entity to use for auto-attributes
exportNIs this service allowed to be accessed via SOAP/HTTP/JMS? (true/false)false
max-retryNSets the max number of times this service will retry when failed (persisted async only)-1 (unlimited)
require-new-transactionNRequire a new transaction for this servicetrue
semaphoreNDefines how concurrent calls to this service should be handled:
none: multiple calls to this service may run concurrently
wait: while this service is running, queue any subsequent calls
fail: while this service is running, fail any subsequent calls
none
semaphore-wait-secondsNWhen semaphore=”wait” how many seconds to wait before failing the service call300
sempahore-sleepNWhen semaphore=”wait” how often (in milliseconds) to check if the waiting service call can be run500
transaction-timeoutNOverride the default transaction timeout, only works if we start the transaction0 (Use system default)
use-transactionNCreate a transaction for this service (if one is not already in place)true
validateNDo we validate the attributes found below for name and type matching? (true/false)true

서비스 요소

구현 요소

  • 서비스 – 이 서비스가 구현하는 서비스의 이름입니다. 모든 속성이 상속됨

속성 요소

  • name – 이 속성의 이름
  • type – 객체 유형(String, java.util.Date 등)
  • 모드 – 입력 또는 출력 매개변수 또는 둘 다(IN/OUT/INOUT)
  • optional – 이 매개변수는 선택 사항입니까(true/ false )*밑줄이 표시된 값은 기본값입니다.

위에서 이 서비스의 이름이 userLogin 이고 Java 엔진을 사용하는 것을 볼 수 있습니다 . 이 서비스에는 두 개의 필수 IN 매개변수, 즉 login.username 및 login.password가 필요합니다 . 필수 매개변수는 서비스가 호출되기 전에 테스트됩니다. 매개변수가 이름 및 개체 유형별로 일치하지 않으면 서비스가 호출되지 않습니다. 서비스에 전송되거나 전송되지 않을 수 있는 매개변수는 선택사항 으로 정의되어야 합니다.. 서비스가 호출된 후 OUT 매개변수가 테스트됩니다. 필수 매개변수만 테스트되지만 선택적 또는 필수로 정의되지 않은 매개변수가 전달되면 서비스가 실패합니다. 이 서비스에는 OUT 매개변수가 필요하지 않으므로 결과만 반환됩니다.


자동 엔티티 유지 관리 서비스 정의

OFBiz는 많은 엔터티에 대한 간단한 생성, 업데이트 및 삭제(CrUD) 작업을 위한 서비스를 자동으로 정의할 수 있습니다.

엔진 속성을 “entity-auto”로 설정하고 invoke 속성을 “create”, “update” 또는 “delete”로 설정합니다. 

예를 들어:

<service name="createInvoiceContactMech" engine="entity-auto" invoke="create" default-entity-name="InvoiceContactMech">
    <description>Create a ContactMech for an invoice</description>
    <permission-service service-name="acctgInvoicePermissionCheck" main-action="CREATE"/>
    <auto-attributes include="pk" mode="IN" optional="false"/>
</service>

entity-auto 엔진은 다음 생성 작업을 구현할 수 있습니다.

  1. 기본 자동 시퀀싱을 위한 단일 OUT 기본 키
  2. 선택적 재정의가 있는 기본 자동 시퀀싱을 위한 단일 INOUT 기본 키
  3. OUT만 있는 마지막 부분을 제외한 모든 부분이 IN인 다중 부분 기본 키(누락된 기본 키는 주로 엔터티 연결을 위한 하위 시퀀스입니다.
  4. 수동으로 지정된 기본 키에 대한 모든 기본 키 필드 IN

더 복잡한 상황의 경우 자동으로 정의된 서비스에 의존하는 대신 자체 서비스에 대한 코드를 작성하십시오.

용법


서비스 프레임워크의 내부 사용은 매우 간단합니다. 웹 응용 프로그램에서 LocalDispatcher는 이벤트의 Session 개체를 통해 액세스할 수 있는 ServletContext에 저장됩니다. 웹 기반이 아닌 응용 프로그램의 경우 GenericDispatcher를 생성하기만 하면 됩니다. GenericDelegator delegator = GenericDelegator.getGenericDelegator(“default”);
LocalDispatcher 디스패처 = new GenericDispatcher(“고유 이름”, 위임자);
이제 서비스를 호출하는 데 사용할 수 있는 디스패처가 있습니다. 테스트 서비스를 호출하려면 IN 매개변수 메시지 가 포함된 컨텍스트에 대한 맵을 생성한 다음 *서비스를 호출합니다.*

Map context = UtilMisc.toMap("message","This is a test.");
Map result = null;
 
try {
    result = dispatcher.runSync("testScv", context);
} catch (GenericServiceException e) {
    e.printStackTrace();
}
 
if (result != null) {
    System.out.println("Result from service: " + (String) result.get("resp"));
}

이제 콘솔을 보고 테스트 서비스가 반향한 내용을 확인하십시오.
테스트 서비스는 core/docs/examples/ServiceTest.java에 있습니다. 이것을 컴파일하여 클래스 경로에 배치해야 합니다.

서비스가 나중에 실행되도록 예약하거나 반복하려면 다음을 사용하십시오.

// This example will schedule a job to run now.
Map context = UtilMisc.toMap("message","This is a test.");
try {
    long startTime = (new Date()).getTime();
    dispatcher.schedule("testScv", context, startTime);
} catch (GenericServiceException e) {     e.printStackTrace();
 
 
// This example will schedule a service to run now and repeat once every 5 seconds a total of 10 times.
Map context = UtilMisc.toMap("message","This is a test.");
try {
    long startTime = (new Date()).getTime();
    int frequency = RecurrenceRule.SECONDLY;
    int interval = 5;
    int count = 10;
    dispatcher.schedule("testScv", context, startTime, frequency, interval, count);
} catch (GenericServiceException e) {
    e.printStackTrace();
}

고급의


서비스 엔진에 많은 ‘고급’ 기능이 추가되었습니다. 아래에서 각각에 대한 예, 정의 및 정보를 찾을 수 있습니다.


인터페이스


인터페이스 서비스 엔진은 동일한 매개변수를 공유하는 서비스를 정의하는 데 도움이 되도록 구현되었습니다. 인터페이스 서비스는 호출할 수 없지만 다른 서비스가 상속하는 정의된 서비스입니다. 각 인터페이스 서비스는 인터페이스 엔진을 사용하여 정의됩니다. 예를 들면 다음과 같습니다.

<service name="testInterface" engine="interface" location="" invoke="">
    <description>A test interface service</description>
    <attribute name="partyId" type="String" mode="IN"/>
    <attribute name="partyTypeId" type="String" mode="IN"/>
    <attribute name="userLoginId" type="org.ofbiz.entity.GenericValue" mode="OUT" optional="true"/>
</service>

**위치 및 호출 필드는 DTD에 필요하므로 인터페이스로 사용할 때 단순히 빈 문자열로 남겨둡니다.

이제 인터페이스가 있으므로 이 인터페이스를 구현하는 서비스를 정의해야 합니다.

<service name="testExample1" engine="simple" location="org/ofbiz/commonapp/common/SomeTestFile.xml" invoke="testExample1">
    <description>A test service which implements testInterface</description>
    <implements service="testInterface"/>
</service>

testExample1 서비스는 testInterface 서비스와 정확히 동일한 필수 및 선택적 속성을 갖습니다. testInterface를 구현하는 모든 서비스는 매개변수/속성도 상속합니다. 필요한 경우 구현 태그와 함께 속성 태그를 포함하여 특정 서비스에 추가 속성을 추가할 수 있습니다. 또한 구현 태그 뒤에 속성을 재정의하여 속성을 재정의할 수도 있습니다.


ECA


ECA(Event Condition Action)는 트리거와 매우 유사합니다. 서비스가 호출되면 이 이벤트에 대해 정의된 ECA가 있는지 확인하기 위해 조회가 수행됩니다. 이벤트에는 인증 전, IN 매개변수 검증 전, 실제 서비스 호출 전, OUT 매개변수 검증 전, 트랜잭션 커밋 전 또는 서비스 반환 전이 포함됩니다. 다음으로 ECA 정의의 각 조건이 평가되고 모두 true로 돌아오면 각 작업이 수행됩니다. 작업은 이미 서비스 컨텍스트에 있는 매개변수와 함께 작동하도록 정의되어야 하는 서비스입니다. 각 ECA가 정의할 수 있는 조건 또는 조치의 수에는 제한이 없습니다.

<service-eca>
    <eca service="testScv" event="commit">
        <condition field-name="message" operator="equals" value="12345"/>
        <action service="testBsh" mode="sync"/>
    </eca>
</service-eca>

팁: 설정 작업을 사용하여 트리거된 서비스의 매개변수 이름을 바꾸거나 예를 들어 값을 삽입할 수 있습니다.

<eca service="setCustRequestStatus" event="commit">
    <condition field-name="oldStatusId" operator="not-equals" value="CRQ_ACCEPTED"/>
    <condition field-name="statusId" operator="equals" value="CRQ_ACCEPTED"/>
    <set field-name="bodyParameters.custRequestId" env-name="custRequestId"/>
    <set field-name="bodyParameters.custRequestName" env-name="custRequestName"/>
    <set field-name="partyIdTo" env-name="fromPartyId"/>
    <set field-name="emailTemplateSettingId" value="CUST_REQ_ACCEPTED"/>
    <action service="sendMailFromTemplateSetting" mode="sync" />
</eca>

ECA tag

Attribute NameRequired?Description
serviceYThe name of the service this ECA is attached to.
eventYThe event on which this ECA will run can be (before): auth, in-validate, out-validate, invoke, commit, or return.
run-on-errorNShould this ECA run if there is an error in the service (default false)

eca 구성요소는 0 또는 그 이상의 조건 또는 조건필드와 1개 이상의 동작 구성요소가 필요합니다.

Condition tag

Attribute NameRequired?Description
map-nameNThe name of the service context field that contains the map that the field to be validated will come from. If not specified the field-name will be treated as a service context field name (an env-name).
field-nameYThe name of the map field that will be compared.
operatorYSpecified the comparison operator must be one of the following: less, greater, less-equals, greater-equals, equals, not-equals, or contains.
valueYThe value that the field will compared to. Must be a String, but can be converted to other types.
typeNThe data type to use for the comparison. Must be one of the following: String, Double, Float, Long, Integer, Date, Time, or Timestamp. If no type is specified the default will be String.
formatNA format specifier to use when converting String objects to other data types, mainly Date, Time and Timestamp.

Condition-field tag

Attribute NameRequired?Description
map-nameNThe name of the service context field that contains the map that the field to be validated will come from. If not specified the field-name will be treated as a method environment field name (an env-name).
field-nameYThe name of the map field that will be compared.
operatorYSpecified the comparison operator must be one of the following: less, greater, less-equals, greater-equals, equals, not-equals, or contains.
to-map-nameNThe name of the service context field that contains the map that the field to be compared will come from. If left empty will default to the map-name, or the method environment if map-name is also unspecified.
to-field-nameNThe name of the to-map field that the main field will be compared to. If left empty will default to the field-name.
typeNThe data type to use for the comparison. Must be one of the following: String, Double, Float, Long, Integer, Date, Time, or Timestamp. If no type is specified the default will be String.
formatNA format specifier to use when converting String objects to other data types, mainly Date, Time and Timestamp.

Action tag

Attribute NameRequired?Description
serviceNThe name of the service this action will invoke.
modeYThe mode in which this service should be invoked. Can be sync or async. Note that async actions will not update the context even when set to true.
result-to-contextNShould the results of the action service update the main service’s context. Default true.
result-to-resultNShould the results of the action service update the main service’s results. If true, the action service’s messages will be appended to the main service’s messages. Default false.
ignore-errorNIgnore any errors caused by the action service. If true the error will cause the original service to fail. Default true.
persistNThe action service store / run. Can be true or false. Only effective when mode is async. Default false.

서비스 그룹


서비스 그룹은 초기 서비스를 호출할 때 실행해야 하는 서비스 집합입니다. 그룹 서비스 엔진을 사용하여 서비스를 정의하고 그룹의 모든 서비스에 필요한 모든 매개변수/속성을 포함합니다. location 속성은 groupservices에 필요하지 않으며 invoke 속성은 실행할 그룹의 이름을 정의합니다. 이 서비스가 호출되면 그룹이 호출되고 그룹에 정의된 서비스가 정의된 대로 호출됩니다.

그룹 정의는 매우 간단하며 하나 이상의 서비스 요소와 함께 그룹 요소를 포함합니다. group 요소에는 그룹이 작동하는 방식을 정의하는 데 사용되는 name 속성과 모드 속성이 포함됩니다. service 요소는 ECA의 action 요소와 매우 유사하며, 차이점은 result-to-context의 기본값입니다.

<service-group>
    <group name="testGroup" send-mode="all">
        <invoke name="testScv" mode="sync"/>
        <invoke name="testBsh" mode="sync"/>
    </group>
</service-group>

노선 서비스


경로 서비스는 routeservice 엔진을 사용하여 정의됩니다. 라우트 서비스가 호출되면 호출이 수행되지 않지만 정의된 모든 ECA는 적절한 이벤트 중에 실행됩니다. 이 유형의 서비스는 자주 사용되지 않지만 서비스에 사용 가능한 ECA 옵션을 활용하여 다른 서비스로 ‘라우팅’하는 데 사용할 수 있습니다.


HTTP 서비스


HTTP 서비스를 사용하는 것은 다른 시스템에 정의된 원격 서비스를 호출하는 방법입니다. 로컬 정의는 원격 정의의 정의와 일치해야 하지만 사용되는 엔진은 http여야 하고 위치는 원격 시스템에서 실행 중인 httpService 이벤트에 대한 완전한 URL이어야 하며 호출은 원격 시스템의 서비스 이름이어야 합니다. 실행을 요청하는 시스템. HTTP 서비스를 수락하려면 원격 시스템에 httpService 이벤트가 탑재되어 있어야 합니다. 기본적으로 commonapp 웹 애플리케이션에는 서비스 요청을 수신하기 위해 이 이벤트가 탑재되어 있습니다. 서비스를 원격으로 실행하려면 원격 시스템의 서비스에 내보내기가 true로 설정되어 있어야 합니다. HTTP 서비스는 본질적으로 동기식입니다.


JMS 서비스


JMS 서비스는 서비스 요청이 JMS 주제/대기열로 전송된다는 점을 제외하면 HTTP 서비스와 매우 유사합니다. 엔진은 jms로 설정되어야 하고, 위치는 serviceengine.xml 파일에 정의된 jms-service의 이름이어야 하고(서비스 구성 문서 참조), 호출은 요청하는 원격 시스템의 서비스 이름이어야 합니다. 실행합니다. JMS 서비스는 본질적으로 비동기식입니다.