logo

const class

haven::HavenNamespace

sys::Obj
  sys::Namespace
    haven::HavenNamespace
//
// Copyright (c) 2008, John Sublett
// Licensed under the Academic Free License version 3.0
//
// History:
//   23 Mar 08  John Sublett  Creation
//

**
** HavenNamespace manages the Namespace of a haven service.
**
** See `docLib::Haven`.
**
const class HavenNamespace : Namespace
{
  // TODO - no documentation
  new make()
  {
  }

  // TODO - no documentation
  new makeFor(Str havenName)
  {
    this.havenName = havenName
  }

  // TODO - no documentation
  HavenService findHaven()
  {
    return (HavenService)Thread.find(havenName)
  }

  **
  ** Create the specified object in the namespace.  For
  ** haven the uri must be null.
  **
  override Uri create(Uri uri, Obj obj)
  {
    if (uri != null)
      throw ArgErr.make("Uri must be null for new haven objects.")
    haven := findHaven
    haven.open
    try
    {
      return haven.create(obj)
    }
    finally
    {
      haven.close
    }
  }

  **
  ** Get the object identified by the specified uri.
  **
  override Obj get(Uri objUri, Bool checked := true)
  {
    haven := findHaven
    haven.open
    try
    {
      relUri := objUri.relTo(uri)
      if (!relUri.isRel)
        throw UnresolvedErr.make("Uri not in namespace: $objUri")

      // at this point the uri is of the form 'pod/Type' or 'pod/Type/id'

      objType := typeFromUri(relUri)
      if (objType == null)
      {
        if (checked)
          throw UnresolvedErr.make("Not found: $objUri")
        else
          return null
      }

      if (!haven.typeTableExists(objType))
        throw UnresolvedErr.make("Type table does not exist: $objType")

      if (relUri.path.size == 2)
        return ObjTable.make(haven, objType)

      objId := idFromUri(haven, objType, relUri)
      if (objId == null)
      {
        if (checked)
          throw HavenErr.make("Not found: $objUri")
        else
          return null
      }

      try
      {
        return haven.read(objType, objId)
      }
      catch(Err e)
      {
        if (checked)
          throw e
        else
          return null
      }
    }
    finally
    {
      haven.close
    }
  }

  **
  ** Update the specified object mapped to the specified uri.
  **
  override Void put(Uri uri, Obj obj)
  {
    haven := findHaven
    haven.open
    try
    {
      // get existing, if not found UnresolvedErr will be thrown
      existing := get(uri)

      // make sure keys are equal because keys cannot be modified
      table := haven.table(obj.type)
      keyCols := table.keyColumns
      keyCols.each |ColDef col|
      {
        if (col.field.get(existing) != col.field.get(obj))
          throw HavenErr.make("Key columns cannot be updated on a put.")
      }

      haven.update(obj)
    }
    finally
    {
      haven.close
    }
  }

  **
  ** Delete the object with the specified uri.
  **
  override Void delete(Uri objUri)
  {
    haven := findHaven
    haven.open
    try
    {
      relUri := objUri.relTo(uri)
      if (!relUri.isRel)
        throw UnresolvedErr.make("Uri not in namespace: $objUri")

      objType := typeFromUri(relUri)
      if (objType == null)
        throw UnresolvedErr.make("Not found: $objUri")

      objId := idFromUri(haven, objType, relUri)
      if (objId == null)
        throw UnresolvedErr.make("Not found: $objUri")

      result := haven.deleteById(objType, objId)
      if (!result)
        throw UnresolvedErr.make("Not found: $objUri")
    }
    finally
    {
      haven.close
    }
  }

//////////////////////////////////////////////////////////////////////////
// Uri mapping
//////////////////////////////////////////////////////////////////////////

  internal Type typeFromUri(Uri relUri)
  {
    if (relUri.path.size < 2)
      return null

    podName := relUri.path[0]
    typeName := relUri.path[1]
    return Pod.find(podName).findType(typeName)
  }

  internal Obj idFromUri(HavenService haven, Type objType, Uri relUri)
  {
    if (relUri.path.size < 3)
      return null

    idStr := relUri.path[2]
    tableDef := haven.table(objType)
    keyCol := tableDef.keyColumns[0]

    if (keyCol.field.of == Str#)
      return idStr
    else
    {
      method := keyCol.field.of.method("fromStr")
      return method.call1(idStr)
    }
  }

  **
  ** Get the uri for the specified object.
  **
  Uri objToUri(Obj obj, HavenService haven := null)
  {
    if (haven == null) haven = findHaven
    id := haven.table(obj.type).keyValue(obj)
    if (uri == null)
      return (obj.type.pod.name + "/" + obj.type.name + "/" + id).toUri
    else
      return (uri.toStr + "/" +
             obj.type.pod.name + "/" + obj.type.name + "/" + id).toUri
  }

  **
  ** Get the uri for the object with the specified type and id.
  **
  Uri idToUri(Type objType, Obj id)
  {
    if (uri == null)
      return (objType.pod.name + "/" + objType.name + "/" + id).toUri
    else
      return (uri.toStr + "/" +
             objType.pod.name + "/" + objType.name + "/" + id).toUri
  }

//////////////////////////////////////////////////////////////////////////
// Fields
//////////////////////////////////////////////////////////////////////////

  // TODO - no documentation
  const Str havenName := "haven"

}