Event Ruler (เรียกว่า Ruler ในส่วนที่เหลือของเอกสารเพื่อความกระชับ) คือไลบรารี Java ที่อนุญาตให้จับคู่ กฎ กับ กิจกรรม เหตุการณ์คือรายการช่องซึ่งอาจกำหนดเป็นคู่ชื่อ/ค่าหรือเป็นออบเจ็กต์ JSON กฎจะเชื่อมโยงชื่อฟิลด์เหตุการณ์กับรายการค่าที่เป็นไปได้ มีเหตุผลสองประการในการใช้ไม้บรรทัด:
สารบัญ:
ง่ายที่สุดที่จะอธิบายด้วยตัวอย่าง
เหตุการณ์คือออบเจ็กต์ JSON นี่คือตัวอย่าง:
{
"version" : "0" ,
"id" : "ddddd4-aaaa-7777-4444-345dd43cc333" ,
"detail-type" : "EC2 Instance State-change Notification" ,
"source" : "aws.ec2" ,
"account" : "012345679012" ,
"time" : "2017-10-02T16:24:49Z" ,
"region" : "us-east-1" ,
"resources" : [
"arn:aws:ec2:us-east-1:123456789012:instance/i-000000aaaaaa00000"
] ,
"detail" : {
"c-count" : 5 ,
"d-count" : 3 ,
"x-limit" : 301.8 ,
"source-ip" : "10.0.0.33" ,
"instance-id" : "i-000000aaaaaa00000" ,
"state" : "running"
}
}
คุณยังสามารถเห็นสิ่งนี้เป็นชุดของคู่ชื่อ/ค่าได้ด้วย เพื่อความกระชับเรานำเสนอเพียงตัวอย่างเท่านั้น Ruler มี API สำหรับจัดเตรียมเหตุการณ์ทั้งในรูปแบบ JSON และเป็นคู่ชื่อ/ค่า:
+--------------+------------------------------------------+
| name | value |
|--------------|------------------------------------------|
| source | "aws.ec2" |
| detail-type | "EC2 Instance State-change Notification" |
| detail.state | "running" |
+--------------+------------------------------------------+
เหตุการณ์ในรูปแบบ JSON อาจจัดให้มีในรูปแบบของสตริง JSON แบบดิบ หรือ Jackson JsonNode ที่แยกวิเคราะห์
กฎในส่วนนี้ตรงกับเหตุการณ์ตัวอย่างด้านบนทั้งหมด:
{
"detail-type" : [ "EC2 Instance State-change Notification" ] ,
"resources" : [ "arn:aws:ec2:us-east-1:123456789012:instance/i-000000aaaaaa00000" ] ,
"detail" : {
"state" : [ "initializing" , "running" ]
}
}
ซึ่งจะจับคู่เหตุการณ์ใดๆ ที่มีค่าที่ให้ไว้สำหรับค่า resource
, detail-type
และ detail.state
โดยไม่สนใจช่องอื่นๆ ในกิจกรรม นอกจากนี้ยังจะจับคู่ด้วยว่าค่าของ detail.state
เคยเป็น "initializing"
หรือไม่
ค่าในกฎจะถูกระบุเป็นอาร์เรย์เสมอ และจับคู่ว่าค่าในเหตุการณ์เป็นหนึ่งในค่าที่ระบุในอาร์เรย์หรือไม่ การอ้างอิงถึง resources
แสดงให้เห็นว่าหากค่าในเหตุการณ์เป็นอาร์เรย์ด้วย กฎจะจับคู่ถ้าจุดตัดระหว่างอาร์เรย์เหตุการณ์และกฎอาร์เรย์ไม่ว่างเปล่า
{
"time" : [ { "prefix" : "2017-10-02" } ]
}
การจับคู่คำนำหน้าจะใช้ได้เฉพาะกับฟิลด์ค่าสตริงเท่านั้น
{
"source" : [ { "prefix" : { "equals-ignore-case" : "EC2" } } ]
}
คำนำหน้าเท่ากับละเว้นการจับคู่ตัวพิมพ์จะใช้ได้เฉพาะกับฟิลด์ค่าสตริงเท่านั้น
{
"source" : [ { "suffix" : "ec2" } ]
}
การจับคู่คำต่อท้ายจะใช้ได้เฉพาะกับฟิลด์ค่าสตริงเท่านั้น
{
"source" : [ { "suffix" : { "equals-ignore-case" : "EC2" } } ]
}
คำต่อท้ายที่ตรงกันจะไม่สนใจตัวพิมพ์เล็กและใหญ่จะใช้ได้เฉพาะกับฟิลด์ค่าสตริงเท่านั้น
{
"source" : [ { "equals-ignore-case" : "EC2" } ]
}
การจับคู่แบบ Equals-ignore-case จะใช้ได้กับฟิลด์ค่าสตริงเท่านั้น
{
"source" : [ { "wildcard" : "Simple*Service" } ]
}
การจับคู่ไวด์การ์ดจะใช้ได้เฉพาะกับฟิลด์ค่าสตริงเท่านั้น ค่าเดียวสามารถมีอักขระตัวแทนตั้งแต่ศูนย์ถึงหลายตัวได้ แต่ไม่อนุญาตให้ใช้อักขระตัวแทนที่ต่อเนื่องกัน เพื่อให้ตรงกับเครื่องหมายดอกจันโดยเฉพาะ อักขระไวด์การ์ดสามารถหลีกได้ด้วยแบ็กสแลช เครื่องหมายแบ็กสแลชสองอันติดต่อกัน (เช่น แบ็กสแลชที่หลีกหนีด้วยแบ็กสแลช) แสดงถึงอักขระแบ็กสแลชจริง ไม่อนุญาตให้ใช้แบ็กสแลชที่หลีกอักขระใดๆ ที่ไม่ใช่เครื่องหมายดอกจันหรือแบ็กสแลช
อะไรก็ได้ยกเว้นการจับคู่จะตรงกับชื่อ: จับคู่อะไรก็ได้ ยกเว้น ที่ระบุไว้ในกฎ
อะไรก็ได้ยกเว้นใช้ได้กับสตริงเดี่ยวและค่าตัวเลขหรือรายการ ซึ่งต้องมีสตริงทั้งหมดหรือตัวเลขทั้งหมด นอกจากนี้ยังอาจใช้กับคำนำหน้า คำต่อท้าย หรือการจับคู่ตัวพิมพ์เล็กและใหญ่ของสตริงหรือรายการสตริงด้วย
เดี่ยวอะไรก็ได้ยกเว้น (สตริงแล้วเป็นตัวเลข):
{
"detail" : {
"state" : [ { "anything-but" : "initializing" } ]
}
}
{
"detail" : {
"x-limit" : [ { "anything-but" : 123 } ]
}
}
อะไรก็ได้ยกเว้นรายการ (สตริง):
{
"detail" : {
"state" : [ { "anything-but" : [ "stopped" , "overloaded" ] } ]
}
}
อะไรก็ได้ยกเว้นรายการ (ตัวเลข):
{
"detail" : {
"x-limit" : [ { "anything-but" : [ 100 , 200 , 300 ] } ]
}
}
อะไรก็ได้ยกเว้นคำนำหน้า:
{
"detail" : {
"state" : [ { "anything-but" : { "prefix" : "init" } } ]
}
}
อะไรก็ได้ยกเว้นรายการคำนำหน้า (สตริง):
{
"detail" : {
"state" : [ { "anything-but" : { "prefix" : [ "init" , "error" ] } } ]
}
}
อะไรก็ได้ยกเว้นคำต่อท้าย:
{
"detail" : {
"instance-id" : [ { "anything-but" : { "suffix" : "1234" } } ]
}
}
รายการอะไรก็ได้ยกเว้นคำต่อท้าย (สตริง):
{
"detail" : {
"instance-id" : [ { "anything-but" : { "suffix" : [ "1234" , "6789" ] } } ]
}
}
อะไรก็ได้แต่ละเว้นกรณี:
{
"detail" : {
"state" : [ { "anything-but" : { "equals-ignore-case" : "Stopped" } } ]
}
}
รายการอะไรก็ได้แต่ไม่สนใจตัวพิมพ์ใหญ่ (สตริง):
{
"detail" : {
"state" : [ { "anything-but" : { "equals-ignore-case" : [ "Stopped" , "OverLoaded" ] } } ]
}
}
อะไรก็ได้ยกเว้นไวด์การ์ด:
{
"detail" : {
"state" : [ { "anything-but" : { "wildcard" : "*/bin/*.jar" } } ]
}
}
อะไรก็ได้ยกเว้นรายการไวด์การ์ด (สตริง):
{
"detail" : {
"state" : [ { "anything-but" : { "wildcard" : [ "*/bin/*.jar" , "*/bin/*.class" ] } } ]
}
}
{
"detail" : {
"c-count" : [ { "numeric" : [ ">" , 0 , "<=" , 5 ] } ] ,
"d-count" : [ { "numeric" : [ "<" , 10 ] } ] ,
"x-limit" : [ { "numeric" : [ "=" , 3.018e2 ] } ]
}
}
ข้างต้น การอ้างอิงถึง c-count
, d-count
และ x-limit
แสดงให้เห็นการจับคู่ตัวเลข และใช้ได้กับค่าที่เป็นตัวเลข JSON เท่านั้น การจับคู่ตัวเลขรองรับความแม่นยำและช่วงเดียวกันกับ double
primitive ของ Java ซึ่งใช้มาตรฐาน IEEE 754 binary64
{
"detail" : {
"source-ip" : [ { "cidr" : "10.0.0.0/24" } ]
}
}
นอกจากนี้ยังใช้งานได้กับที่อยู่ IPv6
มีงานที่ตรงกันทั้งที่มีหรือไม่มีช่องในเหตุการณ์ JSON
กฎด้านล่างจะจับคู่เหตุการณ์ใดๆ ที่มีฟิลด์ detail.c-count ปรากฏ
{
"detail" : {
"c-count" : [ { "exists" : true } ]
}
}
กฎด้านล่างจะจับคู่เหตุการณ์ใดๆ ที่ไม่มีฟิลด์ detail.c-count
{
"detail" : {
"c-count" : [ { "exists" : false } ]
}
}
หมายเหตุ การจับคู่ Exists
ใช้ได้เฉพาะกับโหนดปลาย สุดเท่านั้น มันไม่ทำงานบนโหนดระดับกลาง
ตามตัวอย่าง ตัวอย่างข้างต้น exists : false
จะตรงกับเหตุการณ์ด้านล่าง:
{
"detail-type" : [ "EC2 Instance State-change Notification" ] ,
"resources" : [ "arn:aws:ec2:us-east-1:123456789012:instance/i-000000aaaaaa00000" ] ,
"detail" : {
"state" : [ "initializing" , "running" ]
}
}
แต่จะตรงกับเหตุการณ์ด้านล่างด้วยเนื่องจาก c-count
ไม่ใช่โหนดปลายสุด:
{
"detail-type" : [ "EC2 Instance State-change Notification" ] ,
"resources" : [ "arn:aws:ec2:us-east-1:123456789012:instance/i-000000aaaaaa00000" ] ,
"detail" : {
"state" : [ "initializing" , "running" ]
"c-count" : {
"c1" : 100
}
}
}
{
"time" : [ { "prefix" : "2017-10-02" } ] ,
"detail" : {
"state" : [ { "anything-but" : "initializing" } ] ,
"c-count" : [ { "numeric" : [ ">" , 0 , "<=" , 5 ] } ] ,
"d-count" : [ { "numeric" : [ "<" , 10 ] } ] ,
"x-limit" : [ { "anything-but" : [ 100 , 200 , 300 ] } ] ,
"source-ip" : [ { "cidr" : "10.0.0.0/8" } ]
}
}
ตามตัวอย่างข้างต้นแสดง ไม้บรรทัดจะพิจารณากฎที่จะจับคู่หากฟิลด์ ทั้งหมด ที่มีชื่อในกฎตรงกัน และจะพิจารณาฟิลด์ที่จะจับคู่หากค่าฟิลด์ ใด ๆ ที่ให้มาตรงกัน กล่าวคือ ไม้บรรทัดได้ใช้ตรรกะ "และ" ไปยังทุกฟิลด์ตามค่าเริ่มต้น โดยไม่ต้องใช้ "And" พื้นฐาน
มีสองวิธีในการเข้าถึงเอฟเฟกต์ "หรือ":
ค่าดั้งเดิม "$or" เพื่อให้ลูกค้าอธิบายความสัมพันธ์ "Or" ระหว่างฟิลด์ต่างๆ ในกฎได้โดยตรง
ไม้บรรทัดจะรับรู้ความสัมพันธ์ "หรือ" ก็ต่อ เมื่อกฎตรงตามเงื่อนไขด้านล่าง ทั้งหมด :
/src/main/software/amazon/event/ruler/Constants.java#L38
ตัวอย่างเช่น กฎด้านล่างจะไม่ถูกแยกวิเคราะห์เป็น " หรือ" ความสัมพันธ์เนื่องจาก "ตัวเลข" และ "คำนำหน้า" เป็นคำสำคัญที่สงวนไว้สำหรับไม้บรรทัด {
"$or": [ {"numeric" : 123}, {"prefix": "abc"} ]
}
มิฉะนั้น Ruler จะถือว่า "$or" เป็นชื่อไฟล์ปกติเหมือนกับสตริงอื่นๆ ในกฎ
ปกติ "หรือ":
// Effect of "source" && ("metricName" || "namespace")
{
"source" : [ "aws.cloudwatch" ] ,
"$or" : [
{ "metricName" : [ "CPUUtilization" , "ReadLatency" ] } ,
{ "namespace" : [ "AWS/EC2" , "AWS/ES" ] }
]
}
ขนาน "หรือ":
// Effect of ("metricName" || "namespace") && ("detail.source" || "detail.detail-type")
{
"$or" : [
{ "metricName" : [ "CPUUtilization" , "ReadLatency" ] } ,
{ "namespace" : [ "AWS/EC2" , "AWS/ES" ] }
] ,
"detail" : {
"$or" : [
{ "source" : [ "aws.cloudwatch" ] } ,
{ "detail-type" : [ "CloudWatch Alarm State Change" ] }
]
}
}
"Or" มี "และ" อยู่ข้างใน
// Effect of ("source" && ("metricName" || ("metricType && "namespace") || "scope"))
{
"source" : [ "aws.cloudwatch" ] ,
"$or" : [
{ "metricName" : [ "CPUUtilization" , "ReadLatency" ] } ,
{
"metricType" : [ "MetricType" ] ,
"namespace" : [ "AWS/EC2" , "AWS/ES" ]
} ,
{ "scope" : [ "Service" ] }
]
}
ซ้อนกัน "หรือ" และ "และ"
// Effect of ("source" && ("metricName" || ("metricType && "namespace" && ("metricId" || "spaceId")) || "scope"))
{
"source" : [ "aws.cloudwatch" ] ,
"$or" : [
{ "metricName" : [ "CPUUtilization" , "ReadLatency" ] } ,
{
"metricType" : [ "MetricType" ] ,
"namespace" : [ "AWS/EC2" , "AWS/ES" ] ,
"$or" : [
{ "metricId" : [ 1234 ] } ,
{ "spaceId" : [ 1000 ] }
]
} ,
{ "scope" : [ "Service" ] }
]
}
อาจมีการใช้ "$or" เป็นคีย์ปกติอยู่แล้วในบางแอปพลิเคชัน (แม้ว่าจะพบได้ยากก็ตาม) ในกรณีเหล่านี้ Ruler พยายามอย่างเต็มที่เพื่อรักษาความเข้ากันได้แบบย้อนหลัง เฉพาะเมื่อเงื่อนไข 3 ข้อที่กล่าวมาข้างต้นเท่านั้นที่ไม้บรรทัดจะเปลี่ยนพฤติกรรม เนื่องจากถือว่ากฎของคุณต้องการ OR จริงๆ และได้รับการกำหนดค่าไม่ถูกต้องจนถึงทุกวันนี้ ตัวอย่างเช่น กฎด้านล่างจะยังคงทำงานตามปกติโดยถือว่า "$or" เป็นชื่อช่องปกติในกฎและเหตุการณ์:
{
"source" : [ "aws.cloudwatch" ] ,
"$or" : {
"metricType" : [ "MetricType" ] ,
"namespace" : [ "AWS/EC2" , "AWS/ES" ]
}
}
อ้างถึง /src/test/data/normalRulesWithOrWording.json
สำหรับตัวอย่างเพิ่มเติมที่ Ruler แยกวิเคราะห์ "$or" เป็นชื่อฟิลด์ปกติ
คำหลัก "$or" เป็นความสัมพันธ์แบบ "Or" ดั้งเดิมไม่ควรได้รับการออกแบบให้เป็นช่องปกติทั้งในเหตุการณ์และกฎ Ruler รองรับกฎเดิมโดยที่ "$or" ถูกแยกวิเคราะห์เป็นชื่อฟิลด์ปกติเพื่อรักษาความเข้ากันได้แบบย้อนหลัง และให้เวลาสำหรับทีมในการโยกย้ายการใช้งาน "$or" แบบเดิมออกจากกิจกรรมและกฎของพวกเขาเป็นชื่อไฟล์ปกติ การใช้ "$or" แบบผสมเป็น "Or" ดั้งเดิม และ "$or" เป็นชื่อฟิลด์ปกติไม่ได้รับการสนับสนุนโดยเจตนาโดย Ruler เพื่อหลีกเลี่ยงไม่ให้เกิดความคลุมเครือที่น่าอึดอัดใจอย่างยิ่งใน "$or"
มีสองวิธีในการใช้ไม้บรรทัด คุณสามารถคอมไพล์กฎหลายข้อลงใน "Machine" จากนั้นใช้เมธอด rulesForEvent()
หรือเมธอด rulesForJSONEvent()
อย่างใดอย่างหนึ่งเพื่อตรวจสอบว่ากฎข้อใดตรงกับเหตุการณ์ใดๆ ความแตกต่างระหว่างสองวิธีนี้มีการอธิบายไว้ด้านล่าง การสนทนานี้จะใช้ rulesForEvent()
โดยทั่วไป ยกเว้นในกรณีที่ความแตกต่างมีความสำคัญ
หรือคุณสามารถใช้วิธีการบูลีนแบบคงที่วิธีเดียวเพื่อพิจารณาว่าแต่ละเหตุการณ์ตรงกับกฎเฉพาะหรือไม่
มีเมธอดบูลีนแบบคงที่วิธีเดียว Ruler.matchesRule(event, rule)
- อาร์กิวเมนต์ทั้งสองระบุเป็นสตริง JSON
หมายเหตุ: มีวิธีที่เลิกใช้แล้วอีกวิธีหนึ่งที่เรียกว่า Ruler.matches(event, rule)
ซึ่งไม่ควรใช้เนื่องจากผลลัพธ์ไม่สอดคล้องกับ rulesForJSONEvent()
และ rulesForEvent()
ดูเอกสารประกอบเกี่ยวกับ Ruler.matches(event, rule)
สำหรับรายละเอียด
เวลาในการจับคู่ไม่ขึ้นอยู่กับจำนวนกฎ นี่เป็นตัวเลือกที่ดีที่สุดหากคุณมีกฎที่เป็นไปได้หลายกฎที่คุณต้องการเลือก และโดยเฉพาะอย่างยิ่งหากคุณมีวิธีจัดเก็บเครื่องที่คอมไพล์แล้ว
เวลาที่ตรงกันจะได้รับผลกระทบจากระดับของการไม่กำหนดซึ่งเกิดจากกฎตัวแทนและกฎอื่นๆ ยกเว้นไวด์การ์ด ประสิทธิภาพลดลงเมื่อคำนำหน้ากฎตัวแทนมีจำนวนเพิ่มมากขึ้นซึ่งตรงกับเหตุการณ์กรณีที่เลวร้ายที่สุดทางทฤษฎี เพื่อหลีกเลี่ยงปัญหานี้ กฎไวด์การ์ดที่เกี่ยวข้องกับฟิลด์เหตุการณ์เดียวกันควรหลีกเลี่ยงคำนำหน้าทั่วไปที่นำไปสู่อักขระไวด์การ์ดตัวแรก หากจำเป็นต้องมีคำนำหน้าทั่วไป ให้ใช้จำนวนอักขระตัวแทนขั้นต่ำและจำกัดลำดับอักขระซ้ำที่เกิดขึ้นหลังจากอักขระตัวแทน MachineComplexityEvaluator สามารถใช้เพื่อประเมินเครื่องจักรและกำหนดระดับของการไม่กำหนด หรือ "ความซับซ้อน" (เช่น จำนวนคำนำหน้ากฎไวด์การ์ดที่ตรงกับเหตุการณ์กรณีที่แย่ที่สุดทางทฤษฎี) ต่อไปนี้คือจุดข้อมูลบางส่วนที่แสดงประสิทธิภาพโดยทั่วไปที่ลดลงสำหรับการเพิ่มคะแนนความซับซ้อน
สิ่งสำคัญคือต้องจำกัดความซับซ้อนของเครื่องจักรเพื่อปกป้องแอปพลิเคชันของคุณ มีกลยุทธ์ที่แตกต่างกันอย่างน้อยสองกลยุทธ์ในการจำกัดความซับซ้อนของเครื่องจักร อันไหนที่สมเหตุสมผลมากกว่าอาจขึ้นอยู่กับใบสมัครของคุณ
กลยุทธ์ #1 มีความเหมาะสมมากกว่าในการวัดความซับซ้อนที่แท้จริงของเครื่องจักรที่มีกฎทั้งหมด เมื่อเป็นไปได้ควรใช้กลยุทธ์นี้ ข้อเสียคือ สมมติว่าคุณมีระนาบควบคุมที่อนุญาตให้สร้างกฎได้ครั้งละหนึ่งกฎ ไปจนถึงจำนวนมากมาก จากนั้นสำหรับการดำเนินการควบคุม Plane แต่ละรายการ คุณต้องโหลดกฎที่มีอยู่ทั้งหมดเพื่อทำการตรวจสอบ นี่อาจมีราคาแพงมาก นอกจากนี้ยังเสี่ยงต่อสภาพการแข่งขันอีกด้วย ยุทธศาสตร์ที่ 2 คือการประนีประนอม เกณฑ์ที่ใช้โดยกลยุทธ์ #2 จะต่ำกว่ากลยุทธ์ #1 เนื่องจากเป็นเกณฑ์ต่อกฎ สมมติว่าคุณต้องการความซับซ้อนของเครื่องโดยเพิ่มกฎทั้งหมดไว้ไม่เกิน 300 รายการ จากนั้นด้วยกลยุทธ์ #2 คุณสามารถจำกัดแต่ละเครื่องที่มีกฎเดียวให้มีความซับซ้อน 10 รายการ และอนุญาตให้มี 30 กฎที่มีรูปแบบไวด์การ์ด . ในกรณีที่เลวร้ายที่สุดที่ความซับซ้อนเพิ่มเข้ามาอย่างสมบูรณ์ (ไม่น่าเป็นไปได้) สิ่งนี้จะนำไปสู่เครื่องจักรที่มีความซับซ้อน 300 ข้อเสียคือไม่น่าเป็นไปได้ที่ความซับซ้อนจะถูกบวกอย่างสมบูรณ์ และจำนวนกฎที่ประกอบด้วยไวด์การ์ดจะ อาจถูกจำกัดโดยไม่จำเป็น
สำหรับกลยุทธ์ #2 ขึ้นอยู่กับวิธีการจัดเก็บกฎ อาจจำเป็นต้องเพิ่มแอตทริบิวต์เพิ่มเติมให้กับกฎเพื่อระบุว่ากฎใดที่ไม่สามารถกำหนดได้ (เช่น มีรูปแบบไวด์การ์ด) เพื่อจำกัดจำนวนกฎที่มีไวด์การ์ด
ต่อไปนี้คือข้อมูลโค้ดที่แสดงวิธีจำกัดความซับซ้อนสำหรับรูปแบบที่กำหนด เช่น สำหรับกลยุทธ์ #2
public class Validate {
private void validate ( String pattern , MachineComplexityEvaluator machineComplexityEvaluator ) {
// If we cannot compile, then return exception.
List < Map < String , List < Patterns >>> compilationResult = Lists . newArrayList ();
try {
compilationResult . addAll ( JsonRuleCompiler . compile ( pattern ));
} catch ( Exception e ) {
InvalidPatternException internalException =
EXCEPTION_FACTORY . invalidPatternException ( e . getLocalizedMessage ());
throw ExceptionMapper . mapToModeledException ( internalException );
}
// Validate wildcard patterns. Look for wildcard patterns out of all patterns that have been used.
Machine machine = new Machine ();
int i = 0 ;
for ( Map < String , List < Patterns >> rule : compilationResult ) {
if ( containsWildcard ( rule )) {
// Add rule to machine for complexity evaluation.
machine . addPatternRule ( Integer . toString (++ i ), rule );
}
}
// Machine has all rules containing wildcard match types. See if the complexity is under the limit.
int complexity = machine . evaluateComplexity ( machineComplexityEvaluator );
if ( complexity > MAX_MACHINE_COMPLEXITY ) {
InvalidPatternException internalException = EXCEPTION_FACTORY . invalidPatternException ( "Rule is too complex" );
throw ExceptionMapper . mapToModeledException ( internalException );
}
}
private boolean containsWildcard ( Map < String , List < Patterns >> rule ) {
for ( List < Patterns > fieldPatterns : rule . values ()) {
for ( Patterns fieldPattern : fieldPatterns ) {
if ( fieldPattern . type () == WILDCARD || fieldPattern . type () == ANYTHING_BUT_WILDCARD ) {
return true ;
}
}
}
return false ;
}
}
คลาสหลักที่คุณจะโต้ตอบด้วยการจับคู่กฎที่อิงตามเครื่องของรัฐ วิธีการที่น่าสนใจคือ:
addRule()
- เพิ่มกฎใหม่ให้กับเครื่องdeleteRule()
- ลบกฎออกจากเครื่องrulesForEvent()
/ rulesForJSONEvent()
- ค้นหากฎในเครื่องที่ตรงกับเหตุการณ์ มีสองรสชาติ: Machine
และ GenericMachine<T>
Machine เป็นเพียง GenericMachine<String>
API อ้างถึงประเภททั่วไปว่า "ชื่อ" ซึ่งสะท้อนถึงประวัติ: เวอร์ชันสตริงถูกสร้างขึ้นก่อน และสตริงที่จัดเก็บและส่งคืนถือเป็นชื่อกฎ
เพื่อความปลอดภัย ประเภทที่ใช้ในการ "ตั้งชื่อ" กฎควรไม่เปลี่ยนรูป หากคุณเปลี่ยนเนื้อหาของวัตถุในขณะที่ถูกใช้เป็นชื่อกฎ อาจทำให้การทำงานของไม้บรรทัดหยุดลง
ตัวสร้าง GenericMachine และ Machine สามารถเลือกยอมรับอ็อบเจ็กต์ GenericMachineConfiguration ได้ ซึ่งจะแสดงตัวเลือกการกำหนดค่าต่อไปนี้
ค่าเริ่มต้น: false โดยปกติแล้ว NameStates จะถูกนำมาใช้ซ้ำสำหรับลำดับย่อยและรูปแบบคีย์ที่กำหนด หากมีการเพิ่มลำดับย่อยและรูปแบบคีย์นี้ไว้ก่อนหน้านี้ หรือหากมีการเพิ่มรูปแบบสำหรับลำดับย่อยของคีย์ที่กำหนดแล้ว ดังนั้น ตามค่าเริ่มต้น การใช้ NameState ซ้ำจึงถือเป็นโอกาส แต่ด้วยการตั้งค่าสถานะนี้เป็นจริง การใช้ NameState ซ้ำจะถูกบังคับให้ใช้ลำดับย่อยของคีย์ ซึ่งหมายความว่ารูปแบบแรกที่ถูกเพิ่มสำหรับลำดับย่อยของคีย์จะใช้ NameState อีกครั้ง หากมีการเพิ่มลำดับย่อยของคีย์นั้นมาก่อน ความหมายแต่ละลำดับย่อยของคีย์มี NameState เดียว วิธีนี้จะปรับปรุงการใช้งานหน่วยความจำแบบทวีคูณในบางกรณี แต่จะส่งผลให้มีการจัดเก็บกฎย่อยเพิ่มเติมใน NameStates แต่ละรายการ ซึ่งบางครั้ง Ruler จะวนซ้ำ ซึ่งอาจทำให้เกิดการถดถอยของประสิทธิภาพรันไทม์เล็กน้อย ค่าเริ่มต้นนี้เป็นเท็จสำหรับความเข้ากันได้แบบย้อนหลัง แต่มีแนวโน้มว่าแอปพลิเคชันทั้งหมดยกเว้นที่มีความอ่อนไหวต่อเวลาแฝงมากที่สุดจะได้รับประโยชน์จากการตั้งค่านี้ให้เป็นจริง
นี่เป็นตัวอย่างง่ายๆ พิจารณา:
machine . addRule ( "0" , "{"key1": ["a", "b", "c"]}" ) ;
รูปแบบ "a" จะสร้าง NameState จากนั้นถึงแม้จะมี moreNameStateReuse=false รูปแบบที่สอง ("b") และรูปแบบที่สาม ("c") จะนำ NameState เดียวกันนั้นกลับมาใช้ใหม่ แต่ให้พิจารณาสิ่งต่อไปนี้แทน:
machine . addRule ( "0" , "{"key1": ["a"]}" ) ;
machine . addRule ( "1" , "{"key1": ["b"]}" ) ;
machine . addRule ( "2" , "{"key1": ["c"]}" ) ;
ตอนนี้ ด้วย moreNameStateReuse=false เราจะได้ NameState สามรายการ เนื่องจากรูปแบบแรกที่พบสำหรับลำดับย่อยของคีย์ในการเพิ่มกฎแต่ละรายการจะสร้าง NameState ใหม่ ดังนั้น "a", "b" และ "c" ต่างก็มี NameStates เป็นของตัวเอง อย่างไรก็ตาม ด้วย moreNameStateReuse=true "a" จะสร้าง NameState ใหม่ จากนั้น "b" และ "c" จะใช้ NameState เดียวกันนี้ซ้ำ ซึ่งทำได้โดยการจัดเก็บว่าเรามี NameState สำหรับลำดับคีย์ย่อย "key1" อยู่แล้ว
โปรดทราบว่าไม่สำคัญว่าแต่ละ addRule จะใช้ชื่อกฎที่แตกต่างกันหรือชื่อกฎเดียวกัน
ทุกรูปแบบของเมธอดนี้มีอาร์กิวเมนต์แรกเหมือนกัน นั่นคือ String ซึ่งระบุชื่อของ Rule และส่งคืนโดย rulesForEvent()
อาร์กิวเมนต์ที่เหลือระบุคู่ชื่อ/ค่า อาจมีการระบุไว้ใน JSON ตามตัวอย่างด้านบน (ผ่าน String, Reader, InputStream หรือ byte[]
) หรือเป็น Map<String, List<String>>
โดยที่คีย์คือชื่อฟิลด์และ ค่าคือรายการรายการที่ตรงกันที่เป็นไปได้ จากตัวอย่างข้างต้น จะมีคีย์ชื่อ detail.state
ซึ่งค่าจะเป็นรายการที่มี "initializing"
และ "running"
หมายเหตุ: เมธอดนี้ (และ deleteRule()
) ได้รับการซิงโครไนซ์ ดังนั้นอาจมีเพียงเธรดเดียวเท่านั้นที่สามารถอัปเดตเครื่องได้ตลอดเวลา