Skip to content

Commit

Permalink
Language specification support - added API to descriptors.
Browse files Browse the repository at this point in the history
  • Loading branch information
ledsoft committed Jun 2, 2017
1 parent efb57b0 commit 834f6e9
Show file tree
Hide file tree
Showing 9 changed files with 236 additions and 30 deletions.
4 changes: 4 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
- This could be overwritten with a descriptor passed to EM
- [ ] Add support for `orphanRemoval` attribute in object properties
- [ ] Modify OntoDriver API to support Fetch joins
- [ ] Allow static (annotation, attribute of `@OWLDataProperty`) specification of language of String attributes.
This can be overridden on EM operation level (in descriptor).


## Low Priority
Expand All @@ -37,3 +39,5 @@
- [ ] Research whether we could replace aspectj with cglib-generated proxies

### Currently in Progress

- [ ] Allow specification of language for string attributes of an entity.
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,19 @@

import java.lang.reflect.Field;
import java.net.URI;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.*;

/**
* Defines base descriptor, which is used to specify context information for entities and their fields.
* <p>
* The descriptor hierarchy is a classical <b>Composite</b> pattern.
*
* @author ledvima1
*/
public abstract class Descriptor {

protected final URI context;

protected String language;

protected Descriptor() {
this(null);
}
Expand All @@ -53,6 +50,26 @@ public URI getContext() {
return context;
}

/**
* Gets the language set for this descriptor.
*
* @return Language tag (e.g. en, cs).
*/
public Optional<String> getLanguage() {
return Optional.ofNullable(language);
}

/**
* Sets language tag of this descriptor.
* <p>
* Applies to any possible sub-descriptors as well.
*
* @param languageTag The language tag to use, possibly null, meaning no language preference should be used
*/
public void setLanguage(String languageTag) {
this.language = languageTag;
}

/**
* Gets attribute descriptors specified in this descriptor.
*
Expand Down Expand Up @@ -88,6 +105,17 @@ public URI getContext() {
*/
public abstract void addAttributeContext(Field attribute, URI context);

/**
* Sets language to be used when working (retrieving, persisting) with values of the specified attribute.
* <p>
* Note that setting language in this manner will not have any effect on descriptors of the
* specified attribute previously retrieved from this descriptor.
*
* @param attribute The attribute concerned
* @param languageTag Language tag to use, possibly {@code null}
*/
public abstract void setAttributeLanguage(Field attribute, String languageTag);

/**
* Gets all contexts present in this descriptor.
* <p>
Expand All @@ -100,7 +128,7 @@ public URI getContext() {
public Set<URI> getAllContexts() {
Set<URI> contexts = new HashSet<>();
contexts = getContextsInternal(contexts, new HashSet<>());
return contexts != null ? contexts : Collections.<URI>emptySet();
return contexts != null ? contexts : Collections.emptySet();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,26 @@ public void addAttributeContext(Field attribute, URI context) {
fieldDescriptors.put(attribute, new FieldDescriptor(context, attribute));
}

@Override
public void setLanguage(String languageTag) {
super.setLanguage(languageTag);
fieldDescriptors.values().forEach(d -> d.setLanguage(languageTag));
}

@Override
public void setAttributeLanguage(Field attribute, String languageTag) {
Objects.requireNonNull(attribute);

fieldDescriptors.putIfAbsent(attribute, new FieldDescriptor(null, attribute));
fieldDescriptors.get(attribute).setLanguage(languageTag);
}

@Override
public Descriptor getAttributeDescriptor(FieldSpecification<?, ?> attribute) {
Descriptor d = getFieldDescriptor(attribute.getJavaField());
if (d == null) {
d = createDescriptor(attribute, context);
d.setLanguage(language);
}
return d;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ public void addAttributeContext(Field attribute, URI context) {
// Do nothing
}

/**
* Use {@link #setLanguage(String)} instead.
*/
@Override
public void setAttributeLanguage(Field attribute, String languageTag) {
// Do nothing
}

private Descriptor getFieldDescriptor(Field field) {
if (this.field.equals(field)) {
return this;
Expand Down Expand Up @@ -97,8 +105,6 @@ public boolean equals(Object obj) {
if (getClass() != obj.getClass())
return false;
FieldDescriptor other = (FieldDescriptor) obj;
if (!field.equals(other.field))
return false;
return true;
return field.equals(other.field);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package cz.cvut.kbss.jopa.model.descriptors;

import cz.cvut.kbss.jopa.model.annotations.OWLDataProperty;
import cz.cvut.kbss.jopa.model.metamodel.Attribute;
import org.junit.Test;

import java.lang.reflect.Field;
import java.net.URI;

import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class EntityDescriptorTest {

private static final URI CONTEXT_ONE = URI.create("http://krizik.felk.cvut.cz/ontologies/jopa/contextOne");
private static final URI CONTEXT_TWO = URI.create("http://krizik.felk.cvut.cz/ontologies/jopa/contextTwo");
private static final String LANG = "en";

@Test
public void fieldDescriptorByDefaultInheritsEntityContext() throws Exception {
final EntityDescriptor descriptor = new EntityDescriptor(CONTEXT_ONE);
final Attribute<TestClass, String> att = mock(Attribute.class);
when(att.getJavaField()).thenReturn(TestClass.stringAttField());
final Descriptor result = descriptor.getAttributeDescriptor(att);
assertEquals(CONTEXT_ONE, result.getContext());
}

@Test
public void fieldDescriptorHasItsOwnContextWhenItIsSetForIt() throws Exception {
final EntityDescriptor descriptor = new EntityDescriptor(CONTEXT_ONE);
final Attribute<TestClass, String> att = mock(Attribute.class);
when(att.getJavaField()).thenReturn(TestClass.stringAttField());
descriptor.addAttributeContext(att.getJavaField(), CONTEXT_TWO);

final Descriptor result = descriptor.getAttributeDescriptor(att);
assertEquals(CONTEXT_TWO, result.getContext());
}

@Test
public void fieldDescriptorByDefaultInheritsEntityLanguageTag() throws Exception {
final EntityDescriptor descriptor = new EntityDescriptor();
final Attribute<TestClass, String> att = mock(Attribute.class);
when(att.getJavaField()).thenReturn(TestClass.stringAttField());
descriptor.setLanguage(LANG);
assertTrue(descriptor.getLanguage().isPresent());

final Descriptor result = descriptor.getAttributeDescriptor(att);
assertTrue(result.getLanguage().isPresent());
assertEquals(LANG, result.getLanguage().get());
}

@Test
public void fieldDescriptorInheritsChangeOfLanguageTagFromEntityDescriptor() throws Exception {
final EntityDescriptor descriptor = new EntityDescriptor();
final Attribute<TestClass, String> att = mock(Attribute.class);
when(att.getJavaField()).thenReturn(TestClass.stringAttField());
descriptor.setLanguage(LANG);
final String newLang = "cs";
descriptor.setLanguage(newLang);
final Descriptor result = descriptor.getAttributeDescriptor(att);
assertTrue(result.getLanguage().isPresent());
assertEquals(newLang, result.getLanguage().get());
}

@Test
public void fieldDescriptorHasLanguageSetToItThroughEntityDescriptor() throws Exception {
final EntityDescriptor descriptor = new EntityDescriptor();
final Attribute<TestClass, String> att = mock(Attribute.class);
when(att.getJavaField()).thenReturn(TestClass.stringAttField());
descriptor.setLanguage(LANG);
final String newLang = "cs";
descriptor.setAttributeLanguage(att.getJavaField(), newLang);

final Descriptor result = descriptor.getAttributeDescriptor(att);
assertTrue(result.getLanguage().isPresent());
assertEquals(newLang, result.getLanguage().get());
}

@Test
public void twoEntityDescriptorsAreEqualWhenTheirFieldDescriptorsHaveTheSameContexts() throws Exception {
final EntityDescriptor dOne = new EntityDescriptor(CONTEXT_ONE);
final EntityDescriptor dTwo = new EntityDescriptor(CONTEXT_ONE);
dOne.addAttributeContext(TestClass.stringAttField(), CONTEXT_TWO);
dTwo.addAttributeContext(TestClass.stringAttField(), CONTEXT_TWO);
dOne.addAttributeDescriptor(TestClass.intAttField(), new FieldDescriptor(CONTEXT_ONE, TestClass.intAttField()));
dTwo.addAttributeDescriptor(TestClass.intAttField(), new FieldDescriptor(CONTEXT_ONE, TestClass.intAttField()));

assertTrue(dOne.equals(dTwo));
assertTrue(dTwo.equals(dOne));
assertEquals(dOne.hashCode(), dTwo.hashCode());
}

@Test
public void twoEntityDescriptorsAreNotEqualWhenTheyDifferInFieldContext() throws Exception {
final EntityDescriptor dOne = new EntityDescriptor(CONTEXT_ONE);
final EntityDescriptor dTwo = new EntityDescriptor(CONTEXT_ONE);
dOne.addAttributeContext(TestClass.stringAttField(), CONTEXT_TWO);
dTwo.addAttributeContext(TestClass.stringAttField(), CONTEXT_ONE);

assertFalse(dOne.equals(dTwo));
assertNotEquals(dOne.hashCode(), dTwo.hashCode());
}

@SuppressWarnings("unused")
private static class TestClass {

@OWLDataProperty(iri = "http://krizik.felk.cvut.cz/ontologies/jopa/attributes/stringAtt")
private String stringAtt;

@OWLDataProperty(iri = "http://krizik.felk.cvut.cz/ontologies/jopa/attributes/intAtt")
private Integer intAtt;

private static Field stringAttField() throws NoSuchFieldException {
return TestClass.class.getDeclaredField("stringAtt");
}

private static Field intAttField() throws NoSuchFieldException {
return TestClass.class.getDeclaredField("intAtt");
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/**
* Copyright (C) 2016 Czech Technical University in Prague
*
* <p>
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
Expand All @@ -16,7 +16,6 @@

import cz.cvut.kbss.jopa.CommonVocabulary;
import cz.cvut.kbss.jopa.model.EntityManager;
import cz.cvut.kbss.jopa.test.environment.Triple;
import cz.cvut.kbss.ontodriver.owlapi.util.OwlapiUtils;
import org.semanticweb.owlapi.model.*;

Expand All @@ -41,11 +40,11 @@ public void persistTestData(Collection<Triple> data, EntityManager em) throws Ex
axiom = new AddAxiom(ontology, df.getOWLObjectPropertyAssertionAxiom(op, ind, obj));
} else if (t.getProperty().toString().equals(CommonVocabulary.RDFS_LABEL)) {
final OWLAnnotationProperty ap = df.getOWLAnnotationProperty(IRI.create(t.getProperty()));
final OWLLiteral value = OwlapiUtils.createOWLLiteralFromValue(t.getValue(), df, "en");
final OWLLiteral value = OwlapiUtils.createOWLLiteralFromValue(t.getValue(), df, t.getLanguage());
axiom = new AddAxiom(ontology, df.getOWLAnnotationAssertionAxiom(ap, ind.getIRI(), value));
} else {
final OWLDataProperty dp = df.getOWLDataProperty(IRI.create(t.getProperty()));
final OWLLiteral value = OwlapiUtils.createOWLLiteralFromValue(t.getValue(), df, "en");
final OWLLiteral value = OwlapiUtils.createOWLLiteralFromValue(t.getValue(), df, t.getLanguage());
axiom = new AddAxiom(ontology, df.getOWLDataPropertyAssertionAxiom(dp, ind, value));
}
manager.applyChange(axiom);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/**
* Copyright (C) 2016 Czech Technical University in Prague
*
* <p>
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
Expand All @@ -27,8 +27,7 @@ public class SesameDataPersist {

public void persistTestData(Collection<Triple> data, EntityManager em) throws Exception {
final Repository repository = em.unwrap(Repository.class);
final RepositoryConnection connection = repository.getConnection();
try {
try (final RepositoryConnection connection = repository.getConnection()) {
final ValueFactory vf = connection.getValueFactory();
connection.begin();
for (Triple t : data) {
Expand All @@ -37,13 +36,11 @@ public void persistTestData(Collection<Triple> data, EntityManager em) throws Ex
vf.createIRI(t.getValue().toString()));
} else {
connection.add(vf.createIRI(t.getSubject().toString()), vf.createIRI(t.getProperty().toString()),
SesameUtils.createDataPropertyLiteral(t.getValue(), "en", vf));
SesameUtils.createDataPropertyLiteral(t.getValue(), t.getLanguage(), vf));
}

}
connection.commit();
} finally {
connection.close();
}
}
}

0 comments on commit 834f6e9

Please sign in to comment.