blob: ecfa41a5b6d44a187f5b7fe4233cd9d9c5639457 [file] [log] [blame]
#!/usr/bin/env python
#
# Copyright 2007 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""Serves content for "script" handlers using the Java runtime."""
import google
import os
import os.path
import sys
import threading
from google.appengine.api import appinfo
from google.appengine.tools.devappserver2 import http_runtime
from google.appengine.tools.devappserver2 import instance
from google.appengine.tools.devappserver2 import java_application
# TODO: figure out what's needed to react to file changes
class JavaRuntimeInstanceFactory(instance.InstanceFactory):
"""A factory that creates new Java runtime Instances."""
START_URL_MAP = appinfo.URLMap(
url='/_ah/start',
script='_java_app',
login='admin')
WARMUP_URL_MAP = appinfo.URLMap(
url='/_ah/warmup',
script='_java_app',
login='admin')
FILE_CHANGE_INSTANCE_RESTART_POLICY = instance.ALWAYS
def __init__(self, request_data, runtime_config_getter, module_configuration):
"""Initializer for JavaRuntimeInstanceFactory.
Args:
request_data: A wsgi_request_info.WSGIRequestInfo that will be provided
with request information for use by API stubs.
runtime_config_getter: A function that can be called without arguments
and returns the runtime_config_pb2.RuntimeConfig containing the
configuration for the runtime.
module_configuration: An application_configuration.ModuleConfiguration
instance respresenting the configuration of the module that owns the
runtime.
"""
super(JavaRuntimeInstanceFactory, self).__init__(request_data, 1)
self._runtime_config_getter = runtime_config_getter
self._module_configuration = module_configuration
self._application_lock = threading.Lock()
self._java_application = java_application.JavaApplication(
self._module_configuration)
self._java_command = self._make_java_command()
def _make_java_command(self):
# We should be in .../google/appengine/tools/devappserver2/java_runtime.py
# and we want to find .../google/appengine/tools and thence
# .../google/appengine/tools/java/lib
java_home = os.environ.get('JAVA_HOME')
if java_home and os.path.exists(java_home):
java_bin = os.path.join(java_home, 'bin/java')
else:
java_bin = 'java'
java_dir = os.environ['APP_ENGINE_JAVA_PATH']
if not java_dir or not os.path.exists(java_dir):
tools_dir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
java_dir = os.path.join(tools_dir, 'java')
java_lib_dir = os.path.join(java_dir, 'lib')
assert os.path.isdir(java_lib_dir), java_lib_dir
class_path = os.path.join(java_lib_dir, 'appengine-tools-api.jar')
assert os.path.isfile(class_path), class_path
jdk_overrides_jar = os.path.join(java_lib_dir, 'override',
'appengine-dev-jdk-overrides.jar')
assert os.path.isfile(jdk_overrides_jar), jdk_overrides_jar
return [
java_bin,
'-cp', class_path,
'-Dappengine.sdk.root=' + java_dir,
'-Xbootclasspath/p:' + jdk_overrides_jar,
] + (['-XstartOnFirstThread'] if sys.platform == 'darwin' else []) + [
'com.google.appengine.tools.development.'
'devappserver2.StandaloneInstance'
]
def get_restart_directories(self):
"""Returns a list of directories where changes trigger a restart.
Returns:
A list of directories where changes trigger a restart.
"""
# TODO: implement
return []
def files_changed(self):
"""Called when a file relevant to the factory *might* have changed."""
# TODO: implement
def configuration_changed(self, config_changes):
"""Called when the configuration of the module has changed.
Args:
config_changes: A set containing the changes that occured. See the
*_CHANGED constants in the application_configuration module.
"""
# TODO: implement
def new_instance(self, instance_id, expect_ready_request=False):
"""Create and return a new Instance.
Args:
instance_id: A string or integer representing the unique (per module) id
of the instance.
expect_ready_request: If True then the instance will be sent a special
request (i.e. /_ah/warmup or /_ah/start) before it can handle external
requests.
Returns:
The newly created instance.Instance.
"""
def instance_config_getter():
runtime_config = self._runtime_config_getter()
runtime_config.instance_id = str(instance_id)
return runtime_config
env = self._java_application.get_environment()
with self._application_lock:
proxy = http_runtime.HttpRuntimeProxy(
self._java_command,
instance_config_getter,
self._module_configuration,
env=env,
start_process_flavor=http_runtime.START_PROCESS_FILE)
return instance.Instance(self.request_data,
instance_id,
proxy,
self.max_concurrent_requests,
self.max_background_threads,
expect_ready_request)