1
2
3
4
5
6
7
8
9
10
11
12
13
14 package eu.fbk.rdfpro.util;
15
16 import java.io.IOException;
17 import java.util.Objects;
18 import java.util.function.Function;
19
20 import javax.annotation.Nullable;
21
22 import org.openrdf.model.Resource;
23 import org.openrdf.model.Statement;
24 import org.openrdf.model.URI;
25 import org.openrdf.model.Value;
26 import org.openrdf.query.algebra.StatementPattern;
27 import org.openrdf.query.algebra.Var;
28
29
30
31 public final class StatementTemplate implements Function<Statement, Statement> {
32
33 private final Object subj;
34
35 private final Object pred;
36
37 private final Object obj;
38
39 @Nullable
40 private final Object ctx;
41
42 private final byte subjIndex;
43
44 private final byte predIndex;
45
46 private final byte objIndex;
47
48 private final byte ctxIndex;
49
50 public StatementTemplate(final Object subj, final Object pred, final Object obj,
51 @Nullable final Object ctx) {
52
53 this.subj = check(subj);
54 this.pred = check(pred);
55 this.obj = check(obj);
56 this.ctx = check(ctx);
57
58 this.subjIndex = this.subj instanceof Resource ? 4 : ((StatementComponent) this.subj)
59 .getIndex();
60 this.predIndex = this.pred instanceof Resource ? 5 : ((StatementComponent) this.pred)
61 .getIndex();
62 this.objIndex = this.obj instanceof Resource ? 6 : ((StatementComponent) this.obj)
63 .getIndex();
64 this.ctxIndex = this.ctx == null || this.ctx instanceof Resource ? 7
65 : ((StatementComponent) this.ctx).getIndex();
66 }
67
68 public StatementTemplate(final StatementPattern head) {
69 this(componentFor(head.getSubjectVar()), componentFor(head.getPredicateVar()),
70 componentFor(head.getObjectVar()), componentFor(head.getContextVar()));
71 }
72
73 public StatementTemplate(final StatementPattern head, final StatementPattern body) {
74 this(componentFor(head.getSubjectVar(), body), componentFor(head.getPredicateVar(), body),
75 componentFor(head.getObjectVar(), body), componentFor(head.getContextVar(), body));
76 }
77
78 public StatementTemplate normalize(final Function<? super Value, ?> normalizer) {
79 final Object nsubj = this.subj instanceof StatementComponent ? (Object) this.subj
80 : normalizer.apply((Value) this.subj);
81 final Object npred = this.pred instanceof StatementComponent ? (Object) this.pred
82 : normalizer.apply((Value) this.pred);
83 final Object nobj = this.obj instanceof StatementComponent ? (Object) this.obj
84 : normalizer.apply((Value) this.obj);
85 final Object nctx = this.ctx == null
86 || this.ctx instanceof StatementComponent ? (Object) this.ctx : normalizer
87 .apply((Value) this.ctx);
88 return nsubj == this.subj && npred == this.pred && nobj == this.obj && nctx == this.ctx ? this
89 : new StatementTemplate(nsubj, npred, nobj, nctx);
90 }
91
92 @Override
93 public Statement apply(final Statement stmt) {
94 try {
95 final URI p = (URI) resolve(stmt, this.predIndex);
96 final Resource s = (Resource) resolve(stmt, this.subjIndex);
97 final Resource c = (Resource) resolve(stmt, this.ctxIndex);
98 final Value o = (Value) resolve(stmt, this.objIndex);
99 return Statements.VALUE_FACTORY.createStatement(s, p, o, c);
100 } catch (final Throwable ex) {
101 return null;
102 }
103 }
104
105 public Statement apply(final Statement stmt, final StatementDeduplicator deduplicator) {
106 try {
107 final URI p = (URI) resolve(stmt, this.predIndex);
108 final Resource s = (Resource) resolve(stmt, this.subjIndex);
109 final Resource c = (Resource) resolve(stmt, this.ctxIndex);
110 final Value o = (Value) resolve(stmt, this.objIndex);
111 if (deduplicator.add(s, p, o, c)) {
112 return Statements.VALUE_FACTORY.createStatement(s, p, o, c);
113 }
114 } catch (final Throwable ex) {
115 }
116 return null;
117 }
118
119 private Object resolve(final Statement stmt, final byte index) {
120 switch (index) {
121 case 0:
122 return stmt.getSubject();
123 case 1:
124 return stmt.getPredicate();
125 case 2:
126 return stmt.getObject();
127 case 3:
128 return stmt.getContext();
129 case 4:
130 return this.subj;
131 case 5:
132 return this.pred;
133 case 6:
134 return this.obj;
135 case 7:
136 return this.ctx;
137 default:
138 throw new Error();
139 }
140 }
141
142 @Override
143 public boolean equals(final Object object) {
144 if (object == this) {
145 return true;
146 }
147 if (!(object instanceof StatementTemplate)) {
148 return false;
149 }
150 final StatementTemplate other = (StatementTemplate) object;
151 return this.subj.equals(other.subj) && this.pred.equals(other.pred)
152 && this.obj.equals(other.obj) && Objects.equals(this.ctx, other.ctx);
153 }
154
155 @Override
156 public int hashCode() {
157 return Objects.hash(this.subj, this.pred, this.obj, this.ctx);
158 }
159
160 @Override
161 public String toString() {
162 final StringBuilder builder = new StringBuilder();
163 toStringHelper(this.subj, builder);
164 builder.append(' ');
165 toStringHelper(this.pred, builder);
166 builder.append(' ');
167 toStringHelper(this.obj, builder);
168 builder.append(' ');
169 toStringHelper(this.ctx, builder);
170 return builder.toString();
171 }
172
173 private void toStringHelper(final Object component, final StringBuilder builder) {
174 if (component instanceof StatementComponent) {
175 builder.append('?').append(((StatementComponent) component).getLetter());
176 } else if (component == null) {
177 builder.append("null");
178 } else {
179 try {
180 Statements.formatValue((Value) component, Namespaces.DEFAULT, builder);
181 } catch (final IOException ex) {
182 throw new Error(ex);
183 }
184 }
185 }
186
187 private static Object check(final Object component) {
188 if (component != null && !(component instanceof Value)
189 && !(component instanceof StatementComponent)) {
190 throw new IllegalArgumentException("Illegal component " + component);
191 }
192 return component;
193 }
194
195 private static Object componentFor(final Var var) {
196 if (var == null) {
197 return null;
198 } else if (var.hasValue()) {
199 return var.getValue();
200 } else {
201 switch (var.getName().toLowerCase()) {
202 case "s":
203 return StatementComponent.SUBJECT;
204 case "p":
205 return StatementComponent.PREDICATE;
206 case "o":
207 return StatementComponent.OBJECT;
208 case "c":
209 return StatementComponent.CONTEXT;
210 default:
211 throw new IllegalArgumentException("Could not extract component from "
212 + var.getName());
213 }
214 }
215 }
216
217 private static Object componentFor(final Var var, final StatementPattern body) {
218 if (var == null) {
219 return null;
220 } else if (var.hasValue()) {
221 return var.getValue();
222 } else {
223 final String name = var.getName();
224 final Var subjVar = body.getSubjectVar();
225 final Var predVar = body.getPredicateVar();
226 final Var objVar = body.getObjectVar();
227 final Var ctxVar = body.getContextVar();
228 if (!subjVar.hasValue() && name.equals(subjVar.getName())) {
229 return StatementComponent.SUBJECT;
230 } else if (!predVar.hasValue() && name.equals(predVar.getName())) {
231 return StatementComponent.PREDICATE;
232 } else if (!objVar.hasValue() && name.equals(objVar.getName())) {
233 return StatementComponent.OBJECT;
234 } else if (ctxVar != null && !ctxVar.hasValue() && name.equals(ctxVar.getName())) {
235 return StatementComponent.CONTEXT;
236 }
237 throw new IllegalArgumentException("Could not find variable " + var.getName()
238 + " in pattern " + body);
239 }
240 }
241 }