Skip to content

Commit

Permalink
contained references improvements
Browse files Browse the repository at this point in the history
make work when the references are to a supertype of type hierarchy
  • Loading branch information
pahjbo committed Feb 15, 2024
1 parent d55198a commit 50d2f8b
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 74 deletions.
25 changes: 22 additions & 3 deletions runtime/java/src/main/java/org/ivoa/vodml/ModelContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,55 @@
import java.util.Map;
import java.util.Set;

/**
* A context for storing ephemeral information about a model.
* @author Paul Harrison ([email protected])
* //TODO ensure thread safety.
*/
public class ModelContext {

//force instances to be instantiated via create()
private ModelContext() {

};

private static ModelContext instance;

public ModelContext(Map<Class, ReferenceCache> mm) {
private ModelContext(Map<Class, ReferenceCache> mm) {
this.mm = mm;
}

private Map<Class, ReferenceCache> mm;

public static ModelContext current() {
public static synchronized ModelContext current() {
if (instance != null)
return instance;
else
throw new IllegalStateException("the context has not been set");
}

/**
* create a new model context with the associated reference cache.
* @param m the reference cache.
*/
public static void create(Map<Class, ReferenceCache> m) {
instance = new ModelContext(m);
}

/**
* Return the cache for a particular reference type.
* @param <T> the type of the reference.
* @param clazz the type of the reference.
* @return the cache.
*/
@SuppressWarnings("unchecked")
public <T> ReferenceCache<T> cache(Class<T> clazz) {
return mm.get(clazz);
}

/**
* @return
* List the reference types contained in the context.
* @return the set of types.
*/
@SuppressWarnings("rawtypes")
public Set<Class> containedRefs() {
Expand Down
18 changes: 15 additions & 3 deletions runtime/java/src/main/java/org/ivoa/vodml/nav/ReferenceCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,32 @@
import java.util.Map;


/**
* A reference cache implementation to help with processing of contained references.
* The type parameter is the type of the references contained within the cache instance.
* @author Paul Harrison ([email protected])
* @since 15 Feb 2024
*/
public class ReferenceCache <T> {

private Map<T, T> valmap = new HashMap<>();

public void setValues(List<T> inital, List<T> cloned)
/**
* Store values in the cache.
* @param inital - the original reference.
* @param cloned - the cloned value of the same reference.
*/
public void setValues(List<T> inital, List<T> cloned)
{
for (int i = 0; i < inital.size(); i++) {
valmap.put(inital.get(i), cloned.get(i)) ;
}
}

/**
* @param refcont
* @return
* Get the new instance of the reference.
* @param initial the original value of the reference.
* @return the new instance of the reference.
*/
public T get(T initial) {
return valmap.get(initial);
Expand Down
158 changes: 101 additions & 57 deletions tools/xslt/common-structure-functions.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -85,49 +85,20 @@ note - only define functions in here as it is included in the schematron rules

</xsl:function>


<!-- this means does the model have children in inheritance hierarchy -->
<xsl:function name="vf:hasSubTypes" as="xsd:boolean">
<xsl:param name="vodml-ref"/>
<xsl:choose>
<xsl:when test="$models/key('ellookup',$vodml-ref)">
<xsl:value-of select="count($models//extends[vodml-ref = $vodml-ref])> 0"/>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">type <xsl:value-of select="$vodml-ref"/> not in considered models</xsl:message>
</xsl:otherwise>
</xsl:choose>

</xsl:function>

<xsl:function name="vf:hasSuperTypes" as="xsd:boolean">
<xsl:param name="vodml-ref"/>
<xsl:sequence select="count($models/key('ellookup',$vodml-ref)/extends) > 0"/>
</xsl:function>

<!-- number of supertypes in hierarchy -->
<xsl:function name="vf:numberSupertypes" as="xsd:integer">
<xsl:param name="vodml-ref"/>
<xsl:sequence select="count(vf:baseTypeIds($vodml-ref))"/>
</xsl:function>


<!-- is the type (or supertypes) contained anywhere -->
<xsl:function name="vf:isContained" as="xsd:boolean">
<xsl:function name="vf:subTypeIds" as="xsd:string*">
<xsl:param name="vodml-ref" as="xsd:string"/>
<xsl:choose>
<xsl:when test="$models/key('ellookup',$vodml-ref)">
<xsl:variable name="el" as="element()">
<xsl:copy-of select="$models/key('ellookup',$vodml-ref)" />
</xsl:variable>
<!-- <xsl:message>contained <xsl:value-of select="concat($vodml-ref, ' ', count($models//(attribute|composition)/datatype[vodml-ref=$vodml-ref])>0)"/> </xsl:message>-->
<xsl:choose>
<xsl:when test="not($el/extends)">
<xsl:value-of select="count($models//(attribute|composition)/datatype[vodml-ref=$vodml-ref])>0"/><!-- TODO should this not be just composition? -->
<xsl:when test="count($models//extends[vodml-ref = $vodml-ref])> 0">
<xsl:for-each select="$models//*[extends/vodml-ref = $vodml-ref]">
<!-- <xsl:message><xsl:value-of select="concat('subtype of ',$vodml-ref, ' is ', name)" /></xsl:message>-->
<xsl:sequence select="(vf:asvodmlref(.),vf:subTypeIds(vf:asvodmlref(.)))"/>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="count($models//(attribute|composition)/datatype[vodml-ref=$vodml-ref])>0 or vf:isContained($el/extends/vodml-ref)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
Expand All @@ -137,22 +108,12 @@ note - only define functions in here as it is included in the schematron rules

</xsl:function>

<xsl:function name="vf:containingTypes" as="element()*">
<xsl:param name="vodml-ref" as="xsd:string"/>
<!-- this means does the model have children in inheritance hierarchy -->
<xsl:function name="vf:hasSubTypes" as="xsd:boolean">
<xsl:param name="vodml-ref"/>
<xsl:choose>
<xsl:when test="$models/key('ellookup',$vodml-ref)">
<xsl:variable name="el" as="element()">
<xsl:copy-of select="$models/key('ellookup',$vodml-ref)" />
</xsl:variable>
<!-- <xsl:message>contained <xsl:value-of select="concat($vodml-ref, ' ', count($models//(attribute|composition)/datatype[vodml-ref=$vodml-ref])>0)"/> </xsl:message>-->
<xsl:choose>
<xsl:when test="not($el/extends)">
<xsl:sequence select="$models//objectType[(attribute|composition)/datatype/vodml-ref=$vodml-ref]"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="($models//objectType[(attribute|composition)/datatype/vodml-ref=$vodml-ref] , vf:containingTypes($el/extends/vodml-ref))"/>
</xsl:otherwise>
</xsl:choose>
<xsl:value-of select="count($models//extends[vodml-ref = $vodml-ref])> 0"/>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">type <xsl:value-of select="$vodml-ref"/> not in considered models</xsl:message>
Expand All @@ -161,13 +122,20 @@ note - only define functions in here as it is included in the schematron rules

</xsl:function>

<xsl:function name="vf:referencesInModels" as="xsd:string*">
<xsl:sequence select="distinct-values($models//reference/datatype/vodml-ref)"/>
<xsl:function name="vf:hasSuperTypes" as="xsd:boolean">
<xsl:param name="vodml-ref"/>
<xsl:sequence select="count($models/key('ellookup',$vodml-ref)/extends) > 0"/>
</xsl:function>
<xsl:function name="vf:containedReferencesInModels" as="xsd:string*">
<xsl:sequence select="distinct-values($models//reference/datatype/vodml-ref[vf:isContained(.)])"/>

<!-- number of supertypes in hierarchy -->
<xsl:function name="vf:numberSupertypes" as="xsd:integer">
<xsl:param name="vodml-ref"/>
<xsl:sequence select="count(vf:baseTypeIds($vodml-ref))"/>
</xsl:function>




<xsl:function name="vf:importedModelNames" as="xsd:string*">
<xsl:param name="thisModel" as="xsd:string"/>
<xsl:choose>
Expand All @@ -189,6 +157,14 @@ note - only define functions in here as it is included in the schematron rules
</xsl:choose>

</xsl:function>


<xsl:function name="vf:referencesInModels" as="xsd:string*">
<xsl:sequence select="distinct-values($models//reference/datatype/vodml-ref)"/>
</xsl:function>
<xsl:function name="vf:containedReferencesInModels" as="xsd:string*">
<xsl:sequence select="distinct-values($models//reference/datatype/vodml-ref[vf:isContained(.)])"/>
</xsl:function>
<!-- is the type (sub or base) used as a reference -->

<xsl:function name="vf:referredTo" as="xsd:boolean">
Expand Down Expand Up @@ -220,7 +196,7 @@ note - only define functions in here as it is included in the schematron rules

<!-- return all the reference types in the containment hierarchy of the argument type -->
<xsl:function name="vf:referenceTypesInContainmentHierarchy" as="xsd:string*">
<xsl:param name="vodml-ref"/>
<xsl:param name="vodml-ref" as="xsd:string"/>
<xsl:choose>
<xsl:when test="$models/key('ellookup',$vodml-ref)">
<xsl:variable name="el" as="element()">
Expand All @@ -246,7 +222,18 @@ note - only define functions in here as it is included in the schematron rules

<xsl:function name="vf:hasContainedReferencesInContainmentHierarchy" as="xsd:boolean">
<xsl:param name="vodml-ref"/>
<xsl:sequence select="count(vf:referenceTypesInContainmentHierarchy($vodml-ref)[vf:isTypeContained(.,$vodml-ref)]) != 0"/>
<xsl:param name="root-vodml-ref"/>
<xsl:sequence select="count(vf:referenceTypesInContainmentHierarchy($vodml-ref)[vf:isTypeContainedBelow(.,$root-vodml-ref)]) != 0"/>
</xsl:function>

<xsl:function name="vf:hasContainedReferenceInTypeHierarchy" as="xsd:boolean">
<xsl:param name="vodml-ref"/>
<xsl:variable name="types" as="xsd:string*" >
<xsl:sequence select="for $v in vf:baseTypeIds($vodml-ref) return vf:referenceTypesInContainmentHierarchy($v)"/>
<xsl:sequence select="vf:referenceTypesInContainmentHierarchy($vodml-ref)"/>
<xsl:sequence select="for $v in vf:subTypeIds($vodml-ref) return vf:referenceTypesInContainmentHierarchy($v)"/>
</xsl:variable>
<xsl:sequence select="$types = vf:containedReferencesInModels()"/>
</xsl:function>


Expand Down Expand Up @@ -358,7 +345,59 @@ note - only define functions in here as it is included in the schematron rules
</xsl:choose>
</xsl:function>

<xsl:function name="vf:isTypeContained" as="xsd:boolean">

<!-- is the type (or supertypes) contained anywhere -->
<xsl:function name="vf:isContained" as="xsd:boolean">
<xsl:param name="vodml-ref" as="xsd:string"/>
<xsl:choose>
<xsl:when test="$models/key('ellookup',$vodml-ref)">
<xsl:variable name="el" as="element()">
<xsl:copy-of select="$models/key('ellookup',$vodml-ref)" />
</xsl:variable>
<!-- <xsl:message>contained <xsl:value-of select="concat($vodml-ref, ' ', count($models//(attribute|composition)/datatype[vodml-ref=$vodml-ref])>0)"/> </xsl:message>-->
<xsl:choose>
<xsl:when test="not($el/extends)">
<xsl:value-of select="count($models//(attribute|composition)/datatype[vodml-ref=$vodml-ref])>0"/><!-- TODO should this not be just composition? -->
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="count($models//(attribute|composition)/datatype[vodml-ref=$vodml-ref])>0 or vf:isContained($el/extends/vodml-ref)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">type <xsl:value-of select="$vodml-ref"/> not in considered models</xsl:message>
</xsl:otherwise>
</xsl:choose>

</xsl:function>

<xsl:function name="vf:containingTypes" as="element()*">
<xsl:param name="vodml-ref" as="xsd:string"/>
<xsl:choose>
<xsl:when test="$models/key('ellookup',$vodml-ref)">
<xsl:variable name="el" as="element()">
<xsl:copy-of select="$models/key('ellookup',$vodml-ref)" />
</xsl:variable>
<!-- <xsl:message>contained <xsl:value-of select="concat($vodml-ref, ' ', count($models//(attribute|composition)/datatype[vodml-ref=$vodml-ref])>0)"/> </xsl:message>-->
<xsl:choose>
<xsl:when test="not($el/extends)">
<xsl:sequence select="$models//objectType[(attribute|composition)/datatype/vodml-ref=$vodml-ref]"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="($models//objectType[(attribute|composition)/datatype/vodml-ref=$vodml-ref] , vf:containingTypes($el/extends/vodml-ref))"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">type <xsl:value-of select="$vodml-ref"/> not in considered models</xsl:message>
</xsl:otherwise>
</xsl:choose>

</xsl:function>



<xsl:function name="vf:isTypeContainedBelow" as="xsd:boolean">
<xsl:param name="type-vodml-ref" as="xsd:string" />
<xsl:param name="root-vodml-ref" as="xsd:string"/>
<xsl:variable name="root" select="$models/key('ellookup',$root-vodml-ref)"/>
Expand Down Expand Up @@ -438,7 +477,12 @@ note - only define functions in here as it is included in the schematron rules
</xsl:function>
<xsl:function name="vf:isArrayLike" as="xsd:boolean">
<xsl:param name="el" as="element()"/>
<xsl:sequence select="number($el/multiplicity/minOccurs) > 1 and number($el/multiplicity/maxOccurs) > 1" />
<xsl:sequence select="number($el/multiplicity/minOccurs) gt 1 and number($el/multiplicity/maxOccurs) gt 1" />
</xsl:function>
<xsl:function name="vf:isCollection" as="xsd:boolean">
<xsl:param name="el" as="element()"/>
<xsl:sequence select="number($el/multiplicity/minOccurs) lt 2 and number($el/multiplicity/maxOccurs) != 1" />
</xsl:function>


</xsl:stylesheet>
36 changes: 25 additions & 11 deletions tools/xslt/vo-dml2java.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@

<!-- open file for this class -->
<xsl:message >Writing to Class file <xsl:value-of select="$file"/> base=<xsl:value-of select="vf:baseTypes($vodml-ref)/vf:capitalize(name)"/> haschildren=<xsl:value-of
select="vf:hasSubTypes($vodml-ref)"/> contained=<xsl:value-of select="vf:isContained($vodml-ref)"/> referredto=<xsl:value-of
select="vf:hasSubTypes($vodml-ref)"/> st=<xsl:value-of select="string-join(vf:subTypeIds($vodml-ref),',')"/> contained=<xsl:value-of select="vf:isContained($vodml-ref)"/> referredto=<xsl:value-of
select="vf:referredTo($vodml-ref)"/> ct=<xsl:value-of select="string-join(vf:containingTypes($vodml-ref)/name,',')"/></xsl:message>

<xsl:result-document href="{$file}">
Expand Down Expand Up @@ -375,24 +375,42 @@
</xsl:if>

</xsl:if>
<xsl:if test="not(@abstract)">
<xsl:if test="vf:hasReferencesInContainmentHierarchy(vf:asvodmlref($this))" >

<xsl:if test="vf:hasContainedReferenceInTypeHierarchy(vf:asvodmlref($this))" >

/** updates any cloned references that are contained within the hierarchy. */
public void updateClonedReferences() {
<xsl:if test="$this/extends">
super.updateClonedReferences();
</xsl:if>
<xsl:for-each select="$localmembers">
<xsl:variable name="m" select="$models/key('ellookup',current())"/>
<xsl:choose>
<xsl:when test="$m/name()='reference' and vf:isTypeContained($m/datatype/vodml-ref,vf:asvodmlref($this))">
<xsl:when test="$m/name()='reference' and vf:isContained($m/datatype/vodml-ref)">
this.<xsl:value-of select="concat(vf:javaMemberName($m/name),' = org.ivoa.vodml.ModelContext.current().cache(',vf:JavaType($m/datatype/vodml-ref),'.class).get(this.',vf:javaMemberName($m/name),');')"/>
</xsl:when>
<xsl:when test=" vf:hasContainedReferencesInContainmentHierarchy($m/datatype/vodml-ref,vf:asvodmlref($this))">
if(<xsl:value-of select="concat('this.',vf:javaMemberName($m/name),'!= null')"/>){
<xsl:choose>
<xsl:when test="vf:isCollection($m)">
for( var _x: this.<xsl:value-of select="vf:javaMemberName($m/name)"/>){_x.updateClonedReferences();}
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat('this.',vf:javaMemberName($m/name),'.updateClonedReferences();')"/>
</xsl:otherwise>
</xsl:choose>
}
</xsl:when>
<xsl:otherwise>
// this.<xsl:value-of select="concat(vf:javaMemberName($m/name),' ', vf:hasReferencesInContainmentHierarchy($m/datatype/vodml-ref), ' ', vf:hasContainedReferencesInContainmentHierarchy($m/datatype/vodml-ref))"/>;
// this.<xsl:value-of select="concat(vf:javaMemberName($m/name),' ', vf:hasReferencesInContainmentHierarchy($m/datatype/vodml-ref), ' ', vf:hasContainedReferencesInContainmentHierarchy($m/datatype/vodml-ref,vf:asvodmlref($this)),' ', string-join(vf:referenceTypesInContainmentHierarchy($m/datatype/vodml-ref),','))"/>;
</xsl:otherwise>
</xsl:choose>

</xsl:for-each>
}
</xsl:if>

</xsl:if>
<xsl:if test="not(@abstract)">
/**
* Copy Constructor. Note that references will remain as is rather than be copied.
* @param other the object to be copied.
Expand Down Expand Up @@ -473,11 +491,7 @@
this.<xsl:value-of select="concat($m/name,'=(',$jt,'[])other.',$m/name)"/>;
</xsl:when>
<xsl:when test="$m/multiplicity/maxOccurs != 1">
<xsl:if test="vf:isContained($m/datatype/vodml-ref) and vf:referredTo($m/datatype/vodml-ref)">
// org.ivoa.vodml.nav.ReferenceCache&lt;ReferredLifeCycle&gt; cache = ModelContext.current().cache(org.ivoa.dm.lifecycle.ReferredLifeCycle.class);
// List&lt;ReferredLifeCycle&gt; cloned = other.refandcontained.stream().map(s -> new org.ivoa.dm.lifecycle.ReferredLifeCycle((org.ivoa.dm.lifecycle.ReferredLifeCycle)s )).collect(java.util.stream.Collectors.toList());
// cache.setValues(other.refandcontained, cloned);
</xsl:if>

<!-- TODO consider multiple references -->
if<xsl:value-of select="concat(' (other.',vf:javaMemberName($m/name),' != null ) {')"/><xsl:text>
</xsl:text>
Expand Down

0 comments on commit 50d2f8b

Please sign in to comment.