All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.continual.services.model.impl.ref.math.CollatzSequence Maven / Gradle / Ivy

The newest version!
package io.continual.services.model.impl.ref.math;

import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import org.json.JSONObject;

import io.continual.iam.access.AccessControlEntry;
import io.continual.iam.access.AccessControlList;
import io.continual.services.model.core.ModelObjectFactory;
import io.continual.services.model.core.ModelObjectFactory.ObjectCreateContext;
import io.continual.services.model.core.ModelObjectMetadata;
import io.continual.services.model.core.ModelPathListPage;
import io.continual.services.model.core.ModelQuery;
import io.continual.services.model.core.ModelRelationInstance;
import io.continual.services.model.core.ModelRelationList;
import io.continual.services.model.core.ModelRequestContext;
import io.continual.services.model.core.ModelTraversal;
import io.continual.services.model.core.PageRequest;
import io.continual.services.model.core.data.JsonModelObject;
import io.continual.services.model.core.data.ModelObject;
import io.continual.services.model.core.exceptions.ModelItemDoesNotExistException;
import io.continual.services.model.core.exceptions.ModelRequestException;
import io.continual.services.model.core.exceptions.ModelServiceException;
import io.continual.services.model.impl.common.BaseRelationSelector;
import io.continual.services.model.impl.common.ReadOnlyModel;
import io.continual.util.naming.Name;
import io.continual.util.naming.Path;

public class CollatzSequence extends ReadOnlyModel
{
	@Override
	public void close () {}

	@Override
	public String getId () { return "CollatzSequence"; }

	@Override
	public long getMaxPathLength () { return 100; }

	@Override
	public long getMaxRelnNameLength () { return 10; }

	@Override
	public long getMaxSerializedObjectLength () { return 1024; }

	@Override
	public boolean exists ( ModelRequestContext context, Path objectPath ) 
	{
		try
		{
			return objectPath.isRootPath () || getNumberFrom ( objectPath ) > 0;
		}
		catch ( NumberFormatException x )
		{
			return false;
		}
	}

	@Override
	public ModelPathListPage listChildrenOfPath ( ModelRequestContext context, Path parentPath, PageRequest pr )
	{
		return ModelPathListPage.emptyList ( pr );
	}

	@Override
	public ModelQuery startQuery () throws ModelRequestException
	{
		throw new RuntimeException ( "query is not implemented" );
	}

	@Override
	public ModelTraversal startTraversal () throws ModelRequestException
	{
		throw new RuntimeException ( "traversal is not implemented" );
	}

	private static final AccessControlList kAcl = AccessControlList.builder ()
		.withEntry ( AccessControlEntry.builder ().permit ().operation ( AccessControlList.READ ).forAllUsers ().build () )
		.build ()
	;

	private static final ModelObjectMetadata kMeta = new ModelObjectMetadata ()
	{
		@Override
		public JSONObject toJson () { return new JSONObject (); }

		@Override
		public AccessControlList getAccessControlList () { return kAcl; }

		@Override
		public Set getLockedTypes () { return new TreeSet<> (); }

		@Override
		public long getCreateTimeMs () { return 0L; }

		@Override
		public long getLastUpdateTimeMs () { return 0L; }
	};

	@Override
	public  T load ( ModelRequestContext context, Path objectPath, ModelObjectFactory factory, K userContext ) throws ModelItemDoesNotExistException, ModelServiceException, ModelRequestException
	{
		if ( !exists ( context, objectPath ) )
		{
			throw new ModelItemDoesNotExistException ( objectPath );
		}

		JSONObject data = new JSONObject ();
		if ( !objectPath.isRootPath () )
		{
			data.put ( "number", getNumberFrom ( objectPath ) );
		}

		return factory.create ( new ObjectCreateContext ()
		{
			@Override
			public ModelObjectMetadata getMetadata () { return kMeta; }

			@Override
			public ModelObject getData () { return new JsonModelObject ( data ); }

			@Override
			public K getUserContext () { return userContext; }
		} );
	}

	@Override
	public RelationSelector selectRelations ( Path objectPath )
	{
		return new BaseRelationSelector ( this, objectPath )
		{
			@Override
			public ModelRelationList getRelations ( ModelRequestContext context ) throws ModelServiceException, ModelRequestException
			{
				final Path p = getObject ();

				final LinkedList result = new LinkedList<> ();
				if ( exists ( context, p ) )
				{
					if ( wantInbound () )
					{
						if ( !p.isRootPath () && nameMatches ( kNext ) )
						{
							for ( long prior : prevCollatzFrom ( getNumberFrom ( p ) ) )
							{
								result.add ( ModelRelationInstance.from ( makePathFor ( prior ), kNext, p ) );
							}
						}
					}

					if ( wantOutbound () )
					{
						if ( !p.isRootPath () && nameMatches ( kNext ) )
						{
							result.add ( ModelRelationInstance.from ( p, kNext, makePathFor ( nextCollatzFrom ( getNumberFrom ( p ) ) ) ) );
						}
					}
				}
				return ModelRelationList.simpleListOfCollection ( result );
			}
		};
	};

	private Path makePathFor ( long fib )
	{
		return Path.getRootPath ().makeChildItem ( Name.fromString ( Long.toString ( fib ) ) );
	}

	private long getNumberFrom ( Path objectPath ) throws NumberFormatException
	{
		if ( objectPath.isRootPath () || objectPath.getSegmentList ().size () > 1 )
		{
			throw new NumberFormatException ( "Not formatted as /" );
		}
		return Long.parseLong ( objectPath.getSegment ( 0 ).toString () );
	}

	private long nextCollatzFrom ( long n )
	{
		if ( n < 1 ) return 1;

		if ( n % 2 == 0 )
		{
			return n / 2;
		}
		else
		{
			return ( 3 * n ) + 1;
		}
	}

	private List prevCollatzFrom ( long n )
	{
		final LinkedList result = new LinkedList<> ();
		if ( n < 1 ) return result;

		// two paths "backward"
		result.add ( n * 2 );

		long m = ( n - 1 ) / 3;
		if ( m > 0 )
		{
			result.add ( m );
		}

		return result;
	}

	private static final String kNext = "next";
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy