Esempio n. 1
0
func SetDatabaseURI(uri string) {
	if RT.DB() == nil {
		RT.DatabaseURI = uri
	} else if uri != RT.DatabaseURI {
		rterr.Stop("Cannot rename database after connection to database has been initialized.")
	}
}
/*
Handles requests on the special explore port for methods of the explorer_api.
TODO Really don't like that we have a separate, near duplicate handler function here for
explorer_api serving. DRY violation!!
*/
func explorerHandler(w http.ResponseWriter, r *http.Request) {

	path := r.URL.Path

	pathSegments := strings.Split(path, "/")
	if len(pathSegments) > 0 && len(pathSegments[0]) == 0 {
		pathSegments = pathSegments[1:]
	}
	var queryString string
	// Last one or last one -1 has to have ? removed from it
	if len(pathSegments) > 0 {
		lastPiece := pathSegments[len(pathSegments)-1]
		i := strings.Index(lastPiece, "?")
		if i > -1 {
			queryString = lastPiece[i+1:]
			if i == 0 {
				pathSegments = pathSegments[:len(pathSegments)-1]
			} else {
				pathSegments[len(pathSegments)-1] = lastPiece[:i]
			}
		} else if len(lastPiece) == 0 {
			pathSegments = pathSegments[:len(pathSegments)-1]
		}
	}
	Logln(WEB_, pathSegments)
	Logln(WEB_, queryString)

	var handlerMethod *RMultiMethod

	pkgName := "shared.relish.pl2012/explorer_api/pkg/web"
	var pkg *RPackage
	pkg = RT.Packages[pkgName]
	if pkg == nil {
		rterr.Stop("No web package has been defined in shared.relish.pl2012/explorer_api")
	}

	//    /foo/bar

	remainingPathSegments := pathSegments[:]
	for len(remainingPathSegments) > 0 {
		name := remainingPathSegments[0]
		methodName := underscoresToCamelCase(name)

		handlerMethod = findHandlerMethod(pkg, methodName)
		if handlerMethod != nil {
			Log(WEB_, "1. %s %s\n", pkg.Name, methodName)
			remainingPathSegments = remainingPathSegments[1:]
			Log(WEB_, "    remainingPathSegments: %v\n", remainingPathSegments)
			break
		}
		pkgName += "/" + name
		Log(WEB_, "2. pkgName: %s\n", pkgName)
		nextPkg := RT.Packages[pkgName]
		if nextPkg != nil {
			remainingPathSegments = remainingPathSegments[1:]
			pkg = nextPkg
			continue
		}
		Logln(WEB_, "     package was not found in RT.Packages")

		if strings.HasSuffix(pkgName, "/pkg/web/favicon.ico") {
			handlerMethod = findHandlerMethod(pkg, "icon")
			if handlerMethod != nil {
				Log(WEB_, "%s %s\n", pkg.Name, methodName)
				remainingPathSegments = remainingPathSegments[1:]
				break
			} else {
				http.Error(w, "", http.StatusNotFound)
				return
			}
		}

		// Note that default only handles paths that do not proceed down to
		// a subdirectory controller package.
		handlerMethod = findHandlerMethod(pkg, "default")
		if handlerMethod != nil {
			// remainingPathSegments = remainingPathSegments[1:]
			Log(WEB_, "3. Found default handler method in %s\n", pkg.Name)
			break
		}
		http.Error(w, "404 page or resource not found", http.StatusNotFound)
		return
	}
	if handlerMethod == nil {
		handlerMethod = findHandlerMethod(pkg, "index")
	}
	if handlerMethod == nil {
		http.Error(w, "404 page or resource not found", http.StatusNotFound)
		return
	}

	// RUN THE WEB DIALOG HANDLER METHOD

	Log(WEB_, "Running dialog handler method: %s\n", handlerMethod.Name)

	positionalArgStringValues := remainingPathSegments
	keywordArgStringValues, err := getKeywordArgs(r)
	if err != nil {
		fmt.Println(err)
		fmt.Fprintln(w, err)
		return
	}

	//var files map[string] []*multipart.FileHeader
	//if r.MultipartForm != nil {
	//	  files = r.MultipartForm.File  // Could still be nil
	//   }

	// TODO TODO Should return the InterpreterThread out of here, and
	// Do the commit or rollback later.
	// Or I should demand a thread from the interpreter separately, first, pass it in to
	// RunServiceMethod, then commit or rollback later.

	t := interpreter.NewThread(nil)

	defer interpreter.DeregisterThread(t)

	t.DBT().BeginTransaction("EXCLUSIVE")

	t.SetTransaction(NewTransaction())
	t.SetErr("Uncaught panic while running explorer web app method.")
	defer t.SetTransaction(nil)

	defer t.CommitOrRollback()

	resultObjects, err := interpreter.RunServiceMethod(t,
		handlerMethod,
		positionalArgStringValues,
		keywordArgStringValues,
		r)

	if err != nil {
		fmt.Println(err)
		fmt.Fprintln(w, err)
		return
	}

	err = processResponse(w, r, pkg, handlerMethod.Name, resultObjects, t)
	if err != nil {
		fmt.Println(err)
		fmt.Fprintln(w, err)
		t.SetErr(err.Error())
		return
	}

	t.SetErr("") // Yay! We did not panic

}
func handler(w http.ResponseWriter, r *http.Request) {

	path := r.URL.Path
	possibleDotPos := len(path) - 7
	if possibleDotPos < 0 {
		possibleDotPos = 0
	}
	if (!strings.HasSuffix(path, ".ico")) && (strings.LastIndex(path, ".") > possibleDotPos) && (!strings.Contains(path, "?")) {
		// Serve static content

		// fmt.Fprintln(w, r.URL.Path)

		filePath := webPackageSrcDirPath + "/static" + path
		http.ServeFile(w, r, filePath)

		return
	}

	pathSegments := strings.Split(path, "/")
	if len(pathSegments) > 0 && len(pathSegments[0]) == 0 {
		pathSegments = pathSegments[1:]
	}
	var queryString string
	// Last one or last one -1 has to have ? removed from it
	if len(pathSegments) > 0 {
		lastPiece := pathSegments[len(pathSegments)-1]
		i := strings.Index(lastPiece, "?")
		if i > -1 {
			queryString = lastPiece[i+1:]
			if i == 0 {
				pathSegments = pathSegments[:len(pathSegments)-1]
			} else {
				pathSegments[len(pathSegments)-1] = lastPiece[:i]
			}
		} else if len(lastPiece) == 0 {
			pathSegments = pathSegments[:len(pathSegments)-1]
		}
	}
	Logln(WEB_, pathSegments)
	Logln(WEB_, queryString)

	var handlerMethod *RMultiMethod

	pkgName := RT.RunningArtifact + "/pkg/web"
	var pkg *RPackage
	pkg = RT.Packages[pkgName]
	if pkg == nil {
		rterr.Stop("No web package has been defined in " + RT.RunningArtifact)
	}

	//    /foo/bar

	remainingPathSegments := pathSegments[:]
	for len(remainingPathSegments) > 0 {
		name := remainingPathSegments[0]
		methodName := underscoresToCamelCase(name)

		handlerMethod = findHandlerMethod(pkg, methodName)
		if handlerMethod != nil {
			Log(WEB_, "1. %s %s\n", pkg.Name, methodName)
			remainingPathSegments = remainingPathSegments[1:]
			Log(WEB_, "    remainingPathSegments: %v\n", remainingPathSegments)
			break
		}
		pkgName += "/" + name
		Log(WEB_, "2. pkgName: %s\n", pkgName)
		nextPkg := RT.Packages[pkgName]
		if nextPkg != nil {
			remainingPathSegments = remainingPathSegments[1:]
			pkg = nextPkg
			continue
		}
		Logln(WEB_, "     package was not found in RT.Packages")

		if strings.HasSuffix(pkgName, "/pkg/web/favicon.ico") {
			handlerMethod = findHandlerMethod(pkg, "icon")
			if handlerMethod != nil {
				Log(WEB_, "%s %s\n", pkg.Name, methodName)
				remainingPathSegments = remainingPathSegments[1:]
				break
			} else {
				http.Error(w, "", http.StatusNotFound)
				return
			}
		}

		// Note that default only handles paths that do not proceed down to
		// a subdirectory controller package.
		handlerMethod = findHandlerMethod(pkg, "default")
		if handlerMethod != nil {
			// remainingPathSegments = remainingPathSegments[1:]
			Log(WEB_, "3. Found default handler method in %s\n", pkg.Name)
			break
		}
		http.Error(w, "404 page or resource not found", http.StatusNotFound)
		return
	}
	if handlerMethod == nil {
		handlerMethod = findHandlerMethod(pkg, "index")
	}
	if handlerMethod == nil {
		http.Error(w, "404 page or resource not found", http.StatusNotFound)
		return
	}

	// RUN THE WEB DIALOG HANDLER METHOD

	Log(WEB_, "Running dialog handler method: %s\n", handlerMethod.Name)

	positionalArgStringValues := remainingPathSegments
	keywordArgStringValues, err := getKeywordArgs(r)
	if err != nil {
		fmt.Println(err)
		fmt.Fprintln(w, err)
		return
	}

	//var files map[string] []*multipart.FileHeader
	//if r.MultipartForm != nil {
	//	  files = r.MultipartForm.File  // Could still be nil
	//   }

	// TODO TODO Should return the InterpreterThread out of here, and
	// Do the commit or rollback later.
	// Or I should demand a thread from the interpreter separately, first, pass it in to
	// RunServiceMethod, then commit or rollback later.

	t := interpreter.NewThread(nil)

	defer interpreter.DeregisterThread(t)

	Log(GC2_, "Running dialog handler method: %s\n", handlerMethod.Name)
	Log(GC2_, " Args: %v\n", positionalArgStringValues)
	Log(GC2_, " KW Args: %v\n", keywordArgStringValues)

	// Get annotations of the URL-mapped method.
	// These determine what kind of transaction behaviour it will have.
	// Options:
	// <none>  Wrap method execution and response processing in an IMMEDIATE (reserved for write) TRANSACTION
	// "READ" Wrap method execution and response processing in a DEFERRED TRANSACTION which has done a trial db read.
	// "NOTX" Do not use a long transaction at all. Use AUTOCOMMIT transactions, one per db statement.
	// If not doing any persistence in the service method, use NOTX
	//
	mods, err := interpreter.GetServiceMethodModifiers(handlerMethod)
	if err != nil {
		panic(err)
	}

	if !mods["NOTX"] {

		var transactionType string
		if mods["READ"] {
			transactionType = "DEFERRED"
		} else {
			transactionType = "EXCLUSIVE"
		}

		err := t.DBT().BeginTransaction(transactionType)
		if err != nil {
			fmt.Println(err)
			fmt.Fprintln(w, err)
			t.SetErr(err.Error())
			return
		}
		t.SetTransaction(NewTransaction())

		defer t.SetTransaction(nil)
		defer t.CommitOrRollback()
	}

	t.SetErr("Uncaught panic while running web app method.")

	// fmt.Printf("Began transaction now running dialog handler method: %s\n",handlerMethod.Name)

	resultObjects, err := interpreter.RunServiceMethod(t,
		handlerMethod,
		positionalArgStringValues,
		keywordArgStringValues,
		r)

	// fmt.Printf("Finished running dialog handler method: %s\n",handlerMethod.Name)
	Log(GC2_, "Finished running dialog handler method: %s\n", handlerMethod.Name)
	Log(GC2_, " Args: %v\n", positionalArgStringValues)
	Log(GC2_, " KW Args: %v\n", keywordArgStringValues)

	if err != nil {
		fmt.Println(err)
		fmt.Fprintln(w, err)
		t.SetErr(err.Error())
		return
	}

	err = processResponse(w, r, pkg, handlerMethod.Name, resultObjects, t)
	if err != nil {
		fmt.Println(err)
		fmt.Fprintln(w, err)
		t.SetErr(err.Error())
		return
	}

	t.SetErr("") // Yay! We did not panic
	// fmt.Println("finished processing response of " + handlerMethod.Name)
}