| #!/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) |