github.com/mmatczuk/gohan@v0.0.0-20170206152520-30e45d9bdb69/extension/otto/gohan_resource_management.go (about)

     1  //
     2  // Copyright (C) 2015 NTT Innovation Institute, Inc.
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    12  // implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  
    16  package otto
    17  
    18  import (
    19  	"fmt"
    20  
    21  	"github.com/robertkrimen/otto"
    22  
    23  	"github.com/cloudwan/gohan/extension"
    24  	"github.com/cloudwan/gohan/schema"
    25  	"github.com/cloudwan/gohan/server/resources"
    26  )
    27  
    28  const (
    29  	noEnvironmentForSchemaErrorMessageFormat = "No environment for schema '%s'"
    30  	wrongResponseErrorMessageFormat          = "Wrong response from %s"
    31  	notADictionaryErrorMessageFormat         = "Not a dictionary: '%v'"
    32  )
    33  
    34  func handleChainError(env *Environment, call *otto.FunctionCall, err error) {
    35  	switch err := err.(type) {
    36  	default:
    37  		ThrowOttoException(call, err.Error())
    38  	case resources.ResourceError:
    39  		throwOtto(call, "ResourceException", err.Message, err.Problem)
    40  	case extension.Error:
    41  		exceptionInfo, _ := env.VM.ToValue(err.ExceptionInfo)
    42  		throwOtto(call, "ExtensionException", err.Error(), exceptionInfo)
    43  	}
    44  }
    45  
    46  func init() {
    47  	gohanChainingInit := func(env *Environment) {
    48  		vm := env.VM
    49  		builtins := map[string]interface{}{
    50  			"gohan_model_list": func(call otto.FunctionCall) otto.Value {
    51  				VerifyCallArguments(&call, "gohan_model_list", 3)
    52  				context, err := GetMap(call.Argument(0))
    53  				if err != nil {
    54  					ThrowOttoException(&call, err.Error())
    55  				}
    56  				schemaID, err := GetString(call.Argument(1))
    57  				if err != nil {
    58  					ThrowOttoException(&call, err.Error())
    59  				}
    60  				filterMap, err := GetMap(call.Argument(2))
    61  				if err != nil {
    62  					ThrowOttoException(&call, err.Error())
    63  				}
    64  
    65  				resources, err := GohanModelList(context, schemaID, filterMap)
    66  				if err != nil {
    67  					handleChainError(env, &call, err)
    68  				}
    69  
    70  				value, _ := vm.ToValue(resources)
    71  				return value
    72  			},
    73  			"gohan_model_fetch": func(call otto.FunctionCall) otto.Value {
    74  				VerifyCallArguments(&call, "gohan_model_fetch", 4)
    75  				context, err := GetMap(call.Argument(0))
    76  				if err != nil {
    77  					ThrowOttoException(&call, err.Error())
    78  				}
    79  				schemaID, err := GetString(call.Argument(1))
    80  				if err != nil {
    81  					ThrowOttoException(&call, err.Error())
    82  				}
    83  				resourceID, err := GetString(call.Argument(2))
    84  				if err != nil {
    85  					ThrowOttoException(&call, err.Error())
    86  				}
    87  				tenantIDs, err := GetStringList(call.Argument(3))
    88  				if err != nil {
    89  					tenantIDs = nil
    90  				}
    91  
    92  				resource, err := GohanModelFetch(context, schemaID, resourceID, tenantIDs)
    93  				if err != nil {
    94  					handleChainError(env, &call, err)
    95  				}
    96  
    97  				value, _ := vm.ToValue(resource)
    98  				return value
    99  			},
   100  			"gohan_model_create": func(call otto.FunctionCall) otto.Value {
   101  				VerifyCallArguments(&call, "gohan_model_create", 3)
   102  				context, err := GetMap(call.Argument(0))
   103  				if err != nil {
   104  					ThrowOttoException(&call, err.Error())
   105  				}
   106  				schemaID, err := GetString(call.Argument(1))
   107  				if err != nil {
   108  					ThrowOttoException(&call, err.Error())
   109  				}
   110  				dataMap, err := GetMap(call.Argument(2))
   111  				if err != nil {
   112  					ThrowOttoException(&call, err.Error())
   113  				}
   114  
   115  				resource, err := GohanModelCreate(context, schemaID, dataMap)
   116  				if err != nil {
   117  					handleChainError(env, &call, err)
   118  				}
   119  
   120  				value, _ := vm.ToValue(resource)
   121  				return value
   122  			},
   123  			"gohan_model_update": func(call otto.FunctionCall) otto.Value {
   124  				VerifyCallArguments(&call, "gohan_model_update", 5)
   125  				context, err := GetMap(call.Argument(0))
   126  				if err != nil {
   127  					ThrowOttoException(&call, err.Error())
   128  				}
   129  				schemaID, err := GetString(call.Argument(1))
   130  				if err != nil {
   131  					ThrowOttoException(&call, err.Error())
   132  				}
   133  				resourceID, err := GetString(call.Argument(2))
   134  				if err != nil {
   135  					ThrowOttoException(&call, err.Error())
   136  				}
   137  				dataMap, err := GetMap(call.Argument(3))
   138  				if err != nil {
   139  					ThrowOttoException(&call, err.Error())
   140  				}
   141  				tenantIDs, err := GetStringList(call.Argument(4))
   142  				if err != nil {
   143  					tenantIDs = nil
   144  				}
   145  
   146  				resource, err := GohanModelUpdate(context, schemaID, resourceID, dataMap, tenantIDs)
   147  				if err != nil {
   148  					handleChainError(env, &call, err)
   149  				}
   150  
   151  				value, _ := vm.ToValue(resource)
   152  				return value
   153  			},
   154  			"gohan_model_delete": func(call otto.FunctionCall) otto.Value {
   155  				VerifyCallArguments(&call, "gohan_model_delete", 3)
   156  				context, err := GetMap(call.Argument(0))
   157  				if err != nil {
   158  					ThrowOttoException(&call, err.Error())
   159  				}
   160  				schemaID, err := GetString(call.Argument(1))
   161  				if err != nil {
   162  					ThrowOttoException(&call, err.Error())
   163  				}
   164  				resourceID, err := GetString(call.Argument(2))
   165  				if err != nil {
   166  					ThrowOttoException(&call, err.Error())
   167  				}
   168  
   169  				err = GohanModelDelete(context, schemaID, resourceID)
   170  				if err != nil {
   171  					handleChainError(env, &call, err)
   172  				}
   173  
   174  				return otto.Value{}
   175  			},
   176  		}
   177  
   178  		for name, object := range builtins {
   179  			vm.Set(name, object)
   180  		}
   181  	}
   182  	RegisterInit(gohanChainingInit)
   183  }
   184  
   185  //GohanModelList lists gohan resources and running extensions
   186  func GohanModelList(context map[string]interface{}, schemaID string,
   187  	filterMap map[string]interface{}) (interface{}, error) {
   188  
   189  	currentSchema, err := getSchema(schemaID)
   190  	if err != nil {
   191  		return nil, err
   192  	}
   193  	context["schema"] = currentSchema
   194  	context["path"] = currentSchema.GetPluralURL()
   195  
   196  	filter := map[string]interface{}{}
   197  	for key, value := range filterMap {
   198  		switch value := value.(type) {
   199  		default:
   200  			return nil, fmt.Errorf("Filter not a string nor array of strings")
   201  		case string:
   202  			filter[key] = value
   203  		case []interface{}:
   204  			for _, val := range value {
   205  				v, ok := val.(string)
   206  				if !ok {
   207  					return nil, fmt.Errorf("Filter not a string nor array of strings")
   208  				}
   209  				filter[key] = v
   210  			}
   211  		case []string:
   212  			for _, val := range value {
   213  				filter[key] = val
   214  			}
   215  
   216  		}
   217  	}
   218  
   219  	if err := resources.GetResourcesInTransaction(
   220  		context, currentSchema, filter, nil); err != nil {
   221  		return nil, err
   222  	}
   223  	response, ok := context["response"].(map[string]interface{})
   224  	if !ok {
   225  		return nil, fmt.Errorf("No response")
   226  	}
   227  	resources, ok := response[currentSchema.Plural]
   228  	if !ok {
   229  		return nil, fmt.Errorf(wrongResponseErrorMessageFormat, "GetMultipleResources.")
   230  	}
   231  	return resources, nil
   232  }
   233  
   234  //GohanModelFetch fetch gohan resource and running extensions
   235  func GohanModelFetch(context map[string]interface{}, schemaID string, resourceID string,
   236  	tenantIDs []string) (interface{}, error) {
   237  
   238  	currentSchema, err := getSchema(schemaID)
   239  	if err != nil {
   240  		return nil, err
   241  	}
   242  	context["schema"] = currentSchema
   243  	context["path"] = currentSchema.GetPluralURL()
   244  
   245  	if err := resources.GetSingleResourceInTransaction(
   246  		context, currentSchema, resourceID, tenantIDs); err != nil {
   247  		return nil, err
   248  	}
   249  	response, ok := context["response"].(map[string]interface{})
   250  	if !ok {
   251  		return nil, fmt.Errorf("No response")
   252  	}
   253  	return response[currentSchema.Singular], nil
   254  }
   255  
   256  //GohanModelCreate creates gohan resource and running extensions
   257  func GohanModelCreate(context map[string]interface{}, schemaID string,
   258  	dataMap map[string]interface{}) (interface{}, error) {
   259  
   260  	currentSchema, err := getSchema(schemaID)
   261  	if err != nil {
   262  		return nil, err
   263  	}
   264  	context["schema"] = currentSchema
   265  	context["path"] = currentSchema.GetPluralURL()
   266  
   267  	manager := schema.GetManager()
   268  	resourceObj, err := manager.LoadResource(currentSchema.ID, dataMap)
   269  	if err != nil {
   270  		return nil, err
   271  	}
   272  
   273  	if err := resources.CreateResourceInTransaction(
   274  		context, resourceObj); err != nil {
   275  		return nil, err
   276  	}
   277  	response, ok := context["response"].(map[string]interface{})
   278  	if !ok {
   279  		return nil, fmt.Errorf("No response")
   280  	}
   281  	return response[currentSchema.Singular], nil
   282  }
   283  
   284  //GohanModelUpdate updates gohan resource and running extensions
   285  func GohanModelUpdate(context map[string]interface{}, schemaID string, resourceID string, dataMap map[string]interface{}, tenantIDs []string) (interface{}, error) {
   286  
   287  	currentSchema, err := getSchema(schemaID)
   288  	if err != nil {
   289  		return nil, err
   290  	}
   291  	context["schema"] = currentSchema
   292  	context["path"] = currentSchema.GetPluralURL()
   293  
   294  	err = resources.UpdateResourceInTransaction(context, currentSchema, resourceID, dataMap, tenantIDs)
   295  	if err != nil {
   296  		return nil, err
   297  	}
   298  	response, ok := context["response"].(map[string]interface{})
   299  	if !ok {
   300  		return nil, fmt.Errorf("No response")
   301  	}
   302  	return response[currentSchema.Singular], nil
   303  }
   304  
   305  //GohanModelDelete deletes gohan resources and running extensions
   306  func GohanModelDelete(context map[string]interface{}, schemaID string, resourceID string) error {
   307  
   308  	currentSchema, err := getSchema(schemaID)
   309  	if err != nil {
   310  		return err
   311  	}
   312  	context["schema"] = currentSchema
   313  	context["path"] = currentSchema.GetPluralURL()
   314  
   315  	return resources.DeleteResourceInTransaction(context, currentSchema, resourceID)
   316  }