1
votes

I'm trying to utilize the timetree library in my spring data neo4j 4.0.0 project.

As elaborated in this page, https://github.com/graphaware/neo4j-timetree, I've edited my neo4j.properties file to enable the auto event attaching, add timetree dependency to my gradle, and set a property 'creationDate' in the event node with Long data type. Albeit everything looks as it should be, it still doesn't create any timetree.

Hereby is my neo4j.property file:

# Runtime must be enabled like this
com.graphaware.runtime.enabled=true

# A Runtime module that takes care of attaching the events like this (TT is the ID of the module)
com.graphaware.module.TT.1=com.graphaware.module.timetree.module.TimeTreeModuleBootstrapper

# Nodes which represent events and should be attached automatically have to be defined
com.graphaware.module.TT.event=hasLabel('StructureVersionChange'),hasLabel('RuleVersionChange'),hasLabel('FilterVersionChange')

# Optionally, a property on the event nodes that represents the the time (long) at which the event took place must be specified (defaults to "timestamp")
com.graphaware.module.TT.timestamp=creationDate

# Optionally, a resolution can be specified (defaults to DAY)
com.graphaware.module.TT.resolution=SECOND

# Optionally, a time zone can be specified (defaults to UTC)
com.graphaware.module.TT.timezone=CEST

# Optionally, a relationship type with which the events will be attached to the tree can be specified (defaults to AT_TIME)
com.graphaware.module.TT.relationship=CREATED_ON

# autoAttach must be set to true
com.graphaware.module.TT.autoAttach=true

Actually, before this I tried to use JAVA API version of Timetree for my project, but then I was really confused by the parameter type of the timetree constructor, which is Node. Whereas, in spring my Nodes have types of their classes.

Thank you in advance and your suggestion would be really appreciated!

EDIT:

neo4j.properties

# Runtime must be enabled like this
com.graphaware.runtime.enabled=true

# A Runtime module that takes care of attaching the events like this (TT is the ID of the module)
com.graphaware.module.TT.1=com.graphaware.module.timetree.module.TimeTreeModuleBootstrapper

# Nodes which represent events and should be attached automatically have to be defined
com.graphaware.module.TT.event=hasLabel('FilterVersionChange') || hasLabel('StructureVersionChange') || hasLabel('CodeUnitVersionChange') || hasLabel('RuleVersionChange') || hasLabel('EpisodeVersion')

# Optionally, a property on the event nodes that represents the the time (long) at which the event took place must be specified (defaults to "timestamp")
com.graphaware.module.TT.timestamp=creationDate

# Optionally, a resolution can be specified (defaults to DAY)
com.graphaware.module.TT.resolution=SECOND

# Optionally, a time zone can be specified (defaults to UTC)
com.graphaware.module.TT.timezone=CEST

# Optionally, a relationship type with which the events will be attached to the tree can be specified (defaults to AT_TIME)
com.graphaware.module.TT.relationship=CREATED_ON

# autoAttach must be set to true
com.graphaware.module.TT.autoAttach=true

data/log/neo4j.0.0

May 17, 2015 4:07:42 PM com.sun.jersey.server.impl.application.WebApplicationImpl _initiate
INFO: Initiating Jersey application, version 'Jersey: 1.18.1 02/19/2014 03:28 AM'
May 17, 2015 4:07:42 PM com.sun.jersey.server.impl.application.WebApplicationImpl _initiate
INFO: Initiating Jersey application, version 'Jersey: 1.18.1 02/19/2014 03:28 AM'
May 17, 2015 4:07:43 PM com.sun.jersey.server.impl.application.WebApplicationImpl _initiate
INFO: Initiating Jersey application, version 'Jersey: 1.18.1 02/19/2014 03:28 AM'
May 17, 2015 4:11:39 PM com.sun.jersey.server.impl.application.WebApplicationImpl _initiate
INFO: Initiating Jersey application, version 'Jersey: 1.18.1 02/19/2014 03:28 AM'
May 17, 2015 4:11:39 PM com.sun.jersey.server.impl.application.WebApplicationImpl _initiate
INFO: Initiating Jersey application, version 'Jersey: 1.18.1 02/19/2014 03:28 AM'
May 17, 2015 4:11:39 PM com.sun.jersey.server.impl.application.WebApplicationImpl _initiate
INFO: Initiating Jersey application, version 'Jersey: 1.18.1 02/19/2014 03:28 AM'
May 17, 2015 4:28:49 PM com.sun.jersey.server.impl.application.WebApplicationImpl _initiate
INFO: Initiating Jersey application, version 'Jersey: 1.18.1 02/19/2014 03:28 AM'
May 17, 2015 4:28:49 PM com.sun.jersey.server.impl.application.WebApplicationImpl _initiate
INFO: Initiating Jersey application, version 'Jersey: 1.18.1 02/19/2014 03:28 AM'
May 17, 2015 4:28:49 PM com.sun.jersey.server.impl.application.WebApplicationImpl _initiate
INFO: Initiating Jersey application, version 'Jersey: 1.18.1 02/19/2014 03:28 AM'

data/graph.db/messages

2015-05-17 14:28:46.537+0000 INFO  [o.n.k.i.DiagnosticsManager]: --- INITIALIZED diagnostics START ---
2015-05-17 14:28:46.538+0000 INFO  [o.n.k.i.DiagnosticsManager]: Neo4j Kernel properties:
2015-05-17 14:28:46.541+0000 INFO  [o.n.k.i.DiagnosticsManager]: com.graphaware.module.TT.resolution=DAY
2015-05-17 14:28:46.541+0000 INFO  [o.n.k.i.DiagnosticsManager]: com.graphaware.module.TT.timestamp=creationDate
2015-05-17 14:28:46.541+0000 INFO  [o.n.k.i.DiagnosticsManager]: com.graphaware.module.TT.relationship=CREATED_ON
2015-05-17 14:28:46.541+0000 INFO  [o.n.k.i.DiagnosticsManager]: com.graphaware.module.TT.event=hasLabel('FilterVersionChange') || hasLabel('ArchitectureUnitVersionChange') || hasLabel('CodeUnitVersionChange') || hasLabel('RuleVersionChange') || hasLabel('EpisodeVersion')
2015-05-17 14:28:46.541+0000 INFO  [o.n.k.i.DiagnosticsManager]: store_dir=C:\NEO4J-~1.1\data\graph.db
2015-05-17 14:28:46.541+0000 INFO  [o.n.k.i.DiagnosticsManager]: com.graphaware.runtime.enabled=true
2015-05-17 14:28:46.541+0000 INFO  [o.n.k.i.DiagnosticsManager]: com.graphaware.module.TT.autoAttach=true
2015-05-17 14:28:46.541+0000 INFO  [o.n.k.i.DiagnosticsManager]: remote_shell_enabled=true
2015-05-17 14:28:46.541+0000 INFO  [o.n.k.i.DiagnosticsManager]: com.graphaware.module.TT.timezone=CEST
2015-05-17 14:28:46.541+0000 INFO  [o.n.k.i.DiagnosticsManager]: com.graphaware.module.TT.1=com.graphaware.module.timetree.module.TimeTreeModuleBootstrapper
2015-05-17 14:28:46.544+0000 INFO  [o.n.k.i.DiagnosticsManager]: Diagnostics providers:
2015-05-17 14:28:46.544+0000 INFO  [o.n.k.i.DiagnosticsManager]: org.neo4j.kernel.configuration.Config
...
...
2015-05-17 14:28:48.656+0000 INFO  [o.n.k.i.DiagnosticsManager]: --- STARTED diagnostics for KernelDiagnostics:StoreFiles END ---
2015-05-17 14:28:48.696+0000 INFO  [o.n.k.EmbeddedGraphDatabase]: Database is now ready
2015-05-17 14:28:48.696+0000 INFO  [o.n.s.d.LifecycleManagingDatabase]: Successfully started database
2015-05-17 14:28:48.699+0000 INFO  [o.n.k.i.DiagnosticsManager]: --- SERVER STARTED START ---
2015-05-17 14:28:48.736+0000 INFO  [o.n.s.CommunityNeoServer]: Starting HTTP on port :7474 with 8 threads available
2015-05-17 14:28:48.872+0000 INFO  [o.n.s.CommunityNeoServer]: Enabling HTTPS on port :7473
2015-05-17 14:28:48.989+0000 INFO  [o.n.s.w.Jetty9WebServer]: Mounting static content at [/webadmin] from [webadmin-html]
2015-05-17 14:28:49.023+0000 INFO  [o.n.s.w.Jetty9WebServer]: Mounting static content at [/browser] from [browser]
2015-05-17 14:28:49.956+0000 INFO  [o.n.s.CommunityNeoServer]: Server started on: http://localhost:7474/
2015-05-17 14:28:49.956+0000 INFO  [o.n.s.CommunityNeoServer]: Remote interface ready and available at [http://localhost:7474/]
2015-05-17 14:28:49.956+0000 INFO  [o.n.k.i.DiagnosticsManager]: --- SERVER STARTED END ---

Class Entity

@NodeEntity
public class FilterVersionChange extends UnitVersion {
    @GraphId
    private Long id;

    public FilterVersionChange() {
        super();
    }

    public FilterVersionChange(String description, Date creationDate)
    {
        super(description, creationDate);
    }

    @Relationship(type="CONTAINS", direction = Relationship.OUTGOING)
    private Set<FilterState> filterStates;

    @Relationship(type="PREVIOUS", direction = Relationship.OUTGOING)
    private FilterVersionChange previousFilterVersionChange;

    @Relationship(type="REFERENCES", direction = Relationship.OUTGOING)
    private FilterVersionChange referencedFilterVersionChange;

    @Relationship(type="ADDED", direction = Relationship.OUTGOING)
    private Set<FilterState> newFilterStates;

    @Relationship(type="DELETED", direction = Relationship.OUTGOING)
    private Set<FilterState> deletedFilterStates;

    @Relationship(type="MODIFIED", direction = Relationship.OUTGOING)
    private Set<ModifiedUnitState> modifiedFilterStates;

    public void contains(Set<FilterState> filterStates) {
        this.filterStates = filterStates;
    }

    public void previous(FilterVersionChange previousFilterVersionChange) {
        this.previousFilterVersionChange = previousFilterVersionChange;
    }

    public void references(FilterVersionChange referencedFilterVersionChange) {
        this.referencedFilterVersionChange = referencedFilterVersionChange;
    }

    public void added(Set<FilterState> newFilterStates) {
        this.newFilterStates = newFilterStates;
    }

    public void deleted(Set<FilterState> deletedFilterStates) {
        this.deletedFilterStates = deletedFilterStates;
    }

    public void modified(Set<ModifiedUnitState> modifiedFilterStates) {
        this.modifiedFilterStates = modifiedFilterStates;
    }
}

Repository

@Repository
public interface FilterVersionRepository extends GraphRepository<FilterVersion> {
    @Query("MATCH (project:Project {name:{0}})-[:HAS_FILTER_VERSION]->(filterVersion:FilterVersion {name:{1}}) RETURN filterVersion")
    FilterVersion findFilterVersionByName(String projectName, String filterVersionName);

}

Caller function

public FilterVersionChange createNewFilterVersionChange(String projectName,
                                                            String filterVersionName,
                                                            String filterVersionChangeDescription,
                                                            Set<FilterState> filterStates)
    {
        FilterVersion filterVersion = filterVersionRepository.findFilterVersionByName(projectName, filterVersionName);
        if(filterVersion != null)
        {
            for(FilterState filterState : filterStates)
            {
                Filter filter = new Filter(filterState.getMatchingString(), filterState.getMatchingType());
                filterState.stateOf(filter);
            }
            Set<FilterVersionChange> filterVersionChanges = new HashSet<FilterVersionChange>();
            FilterVersionChange filterVersionChange = new FilterVersionChange(filterVersionChangeDescription, new Date());
            filterVersionChange.contains(filterStates);
            filterVersionChange.added(filterStates);
            filterVersionChanges.add(filterVersionChange);
            filterVersion.tracks(filterVersionChanges);
            filterVersionRepository.save(filterVersion);
            return filterVersionChange;
        }
        else
        {
            return null;
        }
    }

FilterVersion.class

@NodeEntity
public class FilterVersion {
    @GraphId
    private Long id;

    private String name;
    private String description;
    private Date creationDate;

    public FilterVersion() {

    }

    public FilterVersion(String name, String description, Date creationDate) {
        this.name = name;
        this.description = description;
        this.creationDate = creationDate;
    }

    @Relationship(type = "TRACKS", direction = Relationship.OUTGOING)
    private Set<FilterVersionChange> filterVersionChanges;

    @Relationship(type = "HAS_FILTER_VERSION", direction = Relationship.INCOMING)
    private Project project;

    public void setName(String name) {
        this.name = name;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public void setCreationDate(Date creationDate) {
        this.creationDate = creationDate;
    }

    public void tracks(Set<FilterVersionChange> filterVersionChanges) {
        this.filterVersionChanges = filterVersionChanges;
    }

    public void belongsTo(Project project) {
        this.project = project;
    }

    public Project getProject() {
        return project;
    }
}

UnitVersion.class

@NodeEntity
public class UnitVersion {
    @GraphId
    protected Long id;

    private String description;
    private Long creationDate;

    public UnitVersion() {

    }

    public UnitVersion(String description, Date creationDate) {
        this.description = description;
        this.creationDate = creationDate.getTime();
    }

    @Relationship(type = "MAPPED_ON", direction = Relationship.OUTGOING)
    private UnitVersion unitVersion;

    public void setDescription(String description) {
        this.description = description;
    }

    public void setCreationDate(Date creationDate) {
        this.creationDate = creationDate.getTime();
    }

    public void mappedOn(UnitVersion unitVersion) {
        this.unitVersion = unitVersion;
    }
}
2
How have you installed Neo4j? It is an unfortunate fact that the GraphAware Framework only works when you install Neo4j from the .zip download, not the .exe installer. (github.com/graphaware/…)Michal Bachman
I set up my Neo4j using the .exe installer. But I reinstalled it with the .zip installer just now after reading your comment, set up the neo4j.properties file, and it still doesn't work. :(Peter Sie
Could you also post code for the UnitVersion class?Luanne
And the FilterVersion class too pleaseLuanne
Hi @Luanne, I have edited my post.Peter Sie

2 Answers

4
votes

The dependency is only useful if you're using the timetree programatically. If your application is running against a Neo4j server, then you need to download and save to your Neo4j server plugins directory:

a) The GraphAware framework (choose either Community or Enterprise)

b) The TimeTree module

Both can be downloaded from http://graphaware.com/products/

Without this, even with a configuration in neo4j.properties, the GraphAware Runtime isn't started and the timetree will not work.

If you want to run your code via a test, then you need to include the dependencies for the TimeTree and GraphAware Runtime and start the GraphAware Runtime yourself, with code such as:

 GraphAwareRuntime runtime = GraphAwareRuntimeFactory.createRuntime(getDatabase());
        runtime.registerModule(new TimeTreeModule("timetree",
                TimeTreeConfiguration
                        .defaultConfiguration()
                        .with(new NodeInclusionPolicy() {
                            @Override
                            public boolean include(Node node) {
                                return node.hasLabel(DynamicLabel.label("User"));
                            }
                        })

                        })
                        .withRelationshipType(DynamicRelationshipType.withName("CREATED_ON"))
                        .withTimeZone(DateTimeZone.forTimeZone(TimeZone.getTimeZone("GMT+1")))
                        .withTimestampProperty("createdOn")
                        .withResolution(Resolution.DAY)
                ,
                getDatabase()));
        runtime.start();

Then you can write tests such as

 @Test
    public void shouldSaveUser()
    {
        User user = new User( "Michal" );
        user.setCreatedOn(1431937636995l);
        userRepository.save( user );

        assertSameGraph( getDatabase(), "CREATE (u:User:Person {name:'Michal', createdOn:1431937636995})," +
                "(root:TimeTreeRoot)," +
                        "(root)-[:FIRST]->(year:Year {value:2015})," +
                        "(root)-[:CHILD]->(year)," +
                        "(root)-[:LAST]->(year)," +
                        "(year)-[:FIRST]->(month:Month {value:5})," +
                        "(year)-[:CHILD]->(month)," +
                        "(year)-[:LAST]->(month)," +
                        "(month)-[:FIRST]->(day:Day {value:18})," +
                        "(month)-[:CHILD]->(day)," +
                        "(month)-[:LAST]->(day)," +
                        "(day)<-[:CREATED_ON]-(u)"
        );

    }
1
votes

Defining the possible labels for the TimeTree has a little different syntax as explained in the InclusionPolicy documentation https://github.com/graphaware/neo4j-framework/tree/master/common#inclusion-policies

The syntax is the following :

com.graphaware.module.TT.event=hasLabel('StructureVersionChange')||hasLabel('RuleVersionChange')||hasLabel('FilterVersionChange')

For debugging purposes you may want to add these lines to your conf/custom-logback.xml file :

<appender name="EXTENSIONLOG"  class="ch.qos.logback.core.FileAppender">
  <file>data/log/extensions.log</file>
  <encoder>
      <pattern>%date{yyyy-MM-dd HH:mm:ss.SSSZ} %-5level [%logger{15}]: %message%n</pattern>
  </encoder>
</appender>

<logger name="com.graphaware" level="debug">
  <appender-ref ref="EXTENSIONLOG"/>
</logger>

and look at the extensions.log file