Skip to content

Commit 272cb53

Browse files
committed
Added an <all> statement to metamorph.
The statement implements a universal quantor or conjunction operation (logical and-operation). It allows for checking whether all statements contained in the <all> statement generated an output. Using the <all> statement conjunctions can be written in a more expressive way than (ab)using the <combine> statement allows. By default the <all> statement outputs an unamed literal with "true" as value. However, this can be customized. <all name="MyCustomName" value="all-fired"> <data source="data1" /> <data source="data2" /> </all> The <all> statement supports reset and flushWith. Conflicts: src/test/java/org/culturegraph/mf/morph/collectors/CollectorTest.java
1 parent 6b140d6 commit 272cb53

File tree

5 files changed

+290
-3
lines changed

5 files changed

+290
-3
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright 2013 Christoph Böhme
3+
*
4+
* Licensed under the Apache License, Version 2.0 the "License";
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.culturegraph.mf.morph.collectors;
17+
18+
import java.util.HashSet;
19+
import java.util.Set;
20+
21+
import org.culturegraph.mf.morph.Metamorph;
22+
import org.culturegraph.mf.morph.NamedValueSource;
23+
import org.culturegraph.mf.util.StringUtil;
24+
25+
/**
26+
* Corresponds to the <code>&lt;all&gt;</code> tag.
27+
*
28+
* @author Christoph Böhme <[email protected]>
29+
*
30+
*/
31+
public final class All extends AbstractCollect {
32+
33+
private static final String DEFAULT_NAME = "";
34+
private static final String DEFAULT_VALUE = "true";
35+
36+
private final Set<NamedValueSource> sources = new HashSet<NamedValueSource>();
37+
private final Set<NamedValueSource> sourcesLeft = new HashSet<NamedValueSource>();
38+
39+
public All(final Metamorph metamorph) {
40+
super(metamorph);
41+
setNamedValueReceiver(metamorph);
42+
}
43+
44+
@Override
45+
protected void receive(final String name, final String value, final NamedValueSource source) {
46+
sourcesLeft.remove(source);
47+
}
48+
49+
@Override
50+
protected boolean isComplete() {
51+
return sourcesLeft.isEmpty();
52+
}
53+
54+
@Override
55+
protected void clear() {
56+
sourcesLeft.addAll(sources);
57+
}
58+
59+
@Override
60+
protected void emit() {
61+
if (sourcesLeft.isEmpty()) {
62+
final String name = StringUtil.fallback(getName(), DEFAULT_NAME);
63+
final String value = StringUtil.fallback(getValue(), DEFAULT_VALUE);
64+
getNamedValueReceiver().receive(name, value, this, getRecordCount(), getEntityCount());
65+
}
66+
}
67+
68+
@Override
69+
public void onNamedValueSourceAdded(final NamedValueSource namedValueSource) {
70+
sources.add(namedValueSource);
71+
sourcesLeft.add(namedValueSource);
72+
}
73+
74+
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
all org.culturegraph.mf.morph.collectors.All
12
combine org.culturegraph.mf.morph.collectors.Combine
23
choose org.culturegraph.mf.morph.collectors.Choose
34
group org.culturegraph.mf.morph.collectors.Group
@@ -6,4 +7,4 @@ concat org.culturegraph.mf.morph.collectors.Concat
67
tuples org.culturegraph.mf.morph.collectors.Tuples
78
square org.culturegraph.mf.morph.collectors.Square
89
range org.culturegraph.mf.morph.collectors.Range
9-
equalsFilter org.culturegraph.mf.morph.collectors.EqualsFilter
10+
equalsFilter org.culturegraph.mf.morph.collectors.EqualsFilter

src/main/resources/schemata/metamorph.xsd

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,25 @@
212212
</complexType>
213213
</element>
214214

215+
<element name="all">
216+
<annotation>
217+
<documentation>Outputs an unnamed literal with "true" as value if all
218+
contained statements fire. This is essentially a conjunction (logical
219+
and-operation) of all contained statements. The name and value generated
220+
by the all-statement can be customised.</documentation>
221+
</annotation>
222+
<complexType>
223+
<sequence>
224+
<group ref="tns:literal-rule" minOccurs="1" maxOccurs="unbounded" />
225+
</sequence>
226+
<attribute name="name" type="string" use="optional" />
227+
<attribute name="value" type="string" use="optional" />
228+
<attribute name="flushWith" type="string" use="optional" />
229+
<attribute name="reset" type="boolean" use="optional"
230+
default="false" />
231+
</complexType>
232+
</element>
233+
215234
<element name="combine">
216235
<complexType>
217236
<sequence>
@@ -555,6 +574,7 @@
555574

556575
<element ref="tns:group" />
557576
<element ref="tns:data" />
577+
<element ref="tns:all" />
558578
<element ref="tns:choose" />
559579
<element ref="tns:combine" />
560580
<element ref="tns:concat" />
@@ -937,4 +957,4 @@
937957
</attribute>
938958
</complexType>
939959
</element>
940-
</schema>
960+
</schema>
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<metamorph-test version="1.0"
3+
xmlns="http://www.culturegraph.org/metamorph-test" xmlns:mm="http://www.culturegraph.org/metamorph"
4+
xmlns:cgxml="http://www.culturegraph.org/cgxml">
5+
6+
<test-case name="should fire only if all elements fire">
7+
<input type="text/x-cg+xml">
8+
<cgxml:cgxml version="1.0">
9+
<cgxml:records>
10+
<cgxml:record id="1">
11+
<cgxml:literal name="data1" value="A" />
12+
<cgxml:literal name="data2" value="B" />
13+
</cgxml:record>
14+
<cgxml:record id="2">
15+
<cgxml:literal name="data2" value="C" />
16+
</cgxml:record>
17+
</cgxml:records>
18+
</cgxml:cgxml>
19+
</input>
20+
21+
<transformation type="text/x-metamorph+xml">
22+
<mm:metamorph version="1">
23+
<mm:rules>
24+
<mm:all>
25+
<mm:data source="data1" />
26+
<mm:data source="data2" />
27+
</mm:all>
28+
</mm:rules>
29+
</mm:metamorph>
30+
</transformation>
31+
32+
<result type="text/x-cg+xml">
33+
<cgxml:cgxml version="1.0">
34+
<cgxml:records>
35+
<cgxml:record id="1">
36+
<cgxml:literal name="" value="true" />
37+
</cgxml:record>
38+
<cgxml:record id="2">
39+
</cgxml:record>
40+
</cgxml:records>
41+
</cgxml:cgxml>
42+
</result>
43+
</test-case>
44+
45+
<test-case name="should support user-defined name and value">
46+
<input type="text/x-cg+xml">
47+
<cgxml:cgxml version="1.0">
48+
<cgxml:records>
49+
<cgxml:record id="1">
50+
<cgxml:literal name="data1" value="A" />
51+
<cgxml:literal name="data2" value="B" />
52+
</cgxml:record>
53+
</cgxml:records>
54+
</cgxml:cgxml>
55+
</input>
56+
57+
<transformation type="text/x-metamorph+xml">
58+
<mm:metamorph version="1">
59+
<mm:rules>
60+
<mm:all name="ALL" value="found all">
61+
<mm:data source="data1" />
62+
<mm:data source="data2" />
63+
</mm:all>
64+
</mm:rules>
65+
</mm:metamorph>
66+
</transformation>
67+
68+
<result type="text/x-cg+xml">
69+
<cgxml:cgxml version="1.0">
70+
<cgxml:records>
71+
<cgxml:record id="1">
72+
<cgxml:literal name="ALL" value="found all" />
73+
</cgxml:record>
74+
</cgxml:records>
75+
</cgxml:cgxml>
76+
</result>
77+
</test-case>
78+
79+
<test-case name="should fire again if a value changes and reset is false">
80+
<input type="text/x-cg+xml">
81+
<cgxml:cgxml version="1.0">
82+
<cgxml:records>
83+
<cgxml:record id="1">
84+
<cgxml:entity name="entity">
85+
<cgxml:literal name="data1" value="A" />
86+
<cgxml:literal name="data2" value="B" />
87+
</cgxml:entity>
88+
<cgxml:entity name="entity">
89+
<cgxml:literal name="data2" value="C" />
90+
</cgxml:entity>
91+
</cgxml:record>
92+
</cgxml:records>
93+
</cgxml:cgxml>
94+
</input>
95+
96+
<transformation type="text/x-metamorph+xml">
97+
<mm:metamorph version="1">
98+
<mm:rules>
99+
<mm:all>
100+
<mm:data source="entity.data1" />
101+
<mm:data source="entity.data2" />
102+
</mm:all>
103+
</mm:rules>
104+
</mm:metamorph>
105+
</transformation>
106+
107+
<result type="text/x-cg+xml">
108+
<cgxml:cgxml version="1.0">
109+
<cgxml:records>
110+
<cgxml:record id="1">
111+
<cgxml:literal name="" value="true" />
112+
<cgxml:literal name="" value="true" />
113+
</cgxml:record>
114+
</cgxml:records>
115+
</cgxml:cgxml>
116+
</result>
117+
</test-case>
118+
119+
<test-case name="should not fire again if only one value changes and reset is true">
120+
<input type="text/x-cg+xml">
121+
<cgxml:cgxml version="1.0">
122+
<cgxml:records>
123+
<cgxml:record id="1">
124+
<cgxml:entity name="entity">
125+
<cgxml:literal name="data1" value="A" />
126+
<cgxml:literal name="data2" value="B" />
127+
</cgxml:entity>
128+
<cgxml:entity name="entity">
129+
<cgxml:literal name="data2" value="B" />
130+
</cgxml:entity>
131+
</cgxml:record>
132+
</cgxml:records>
133+
</cgxml:cgxml>
134+
</input>
135+
136+
<transformation type="text/x-metamorph+xml">
137+
<mm:metamorph version="1">
138+
<mm:rules>
139+
<mm:all reset="true">
140+
<mm:data source="entity.data1" />
141+
<mm:data source="entity.data2" />
142+
</mm:all>
143+
</mm:rules>
144+
</mm:metamorph>
145+
</transformation>
146+
147+
<result type="text/x-cg+xml">
148+
<cgxml:cgxml version="1.0">
149+
<cgxml:records>
150+
<cgxml:record id="1">
151+
<cgxml:literal name="" value="true" />
152+
</cgxml:record>
153+
</cgxml:records>
154+
</cgxml:cgxml>
155+
</result>
156+
</test-case>
157+
158+
<test-case name="should not fire if flushing an incomplete collection">
159+
<input type="text/x-cg+xml">
160+
<cgxml:cgxml version="1.0">
161+
<cgxml:records>
162+
<cgxml:record id="1">
163+
<cgxml:entity name="entity">
164+
<cgxml:literal name="data1" value="A" />
165+
</cgxml:entity>
166+
</cgxml:record>
167+
</cgxml:records>
168+
</cgxml:cgxml>
169+
</input>
170+
171+
<transformation type="text/x-metamorph+xml">
172+
<mm:metamorph version="1">
173+
<mm:rules>
174+
<mm:all flushWith="entity">
175+
<mm:data source="entity.data1" />
176+
<mm:data source="entity.data2" />
177+
</mm:all>
178+
</mm:rules>
179+
</mm:metamorph>
180+
</transformation>
181+
182+
<result type="text/x-cg+xml">
183+
<cgxml:cgxml version="1.0">
184+
<cgxml:records>
185+
<cgxml:record id="1">
186+
</cgxml:record>
187+
</cgxml:records>
188+
</cgxml:cgxml>
189+
</result>
190+
</test-case>
191+
192+
</metamorph-test>

src/test/java/org/culturegraph/mf/morph/collectors/CollectorTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
* @author Markus Michael Geipel
2525
*/
2626
@RunWith(TestSuite.class)
27-
@TestDefinitions({ "CombineTest.xml", "GroupTest.xml", "ChooseTest.xml", "EntityTest.xml", "ConcatTest.xml",
27+
@TestDefinitions({ "AllTest.xml", "CombineTest.xml", "GroupTest.xml", "ChooseTest.xml", "EntityTest.xml", "ConcatTest.xml",
2828
"Nested.xml", "NestedEntity.xml", "TuplesTest.xml", "Misc.xml", "SquareTest.xml", "RangeTest.xml", "EqualsFilterTest.xml" })
2929
public final class CollectorTest {/* bind to xml test */
3030
}

0 commit comments

Comments
 (0)