{"id":231121,"date":"2024-06-11T16:26:46","date_gmt":"2024-06-11T23:26:46","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/java\/?p=231121"},"modified":"2024-06-11T16:36:16","modified_gmt":"2024-06-11T23:36:16","slug":"using-java-with-aca-dynamic-sessions","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/java\/using-java-with-aca-dynamic-sessions\/","title":{"rendered":"Using Java with ACA dynamic sessions"},"content":{"rendered":"<p>Have you ever needed to just run your Java code in an instant-on container in the cloud without the hassle of managing your own Kubernetes server?\u00a0 How about having access to Open AI code interpreter built-in to that container and billed on a consumption basis?<\/p>\n<p><iframe title=\"YouTube video player\" src=\"\/\/www.youtube.com\/embed\/yCo4catePso?si=fqLT6PwBWv1cg181\" width=\"560\" height=\"315\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\"><\/iframe><\/p>\n<h3>About Azure Container Apps and dynamic sessions<\/h3>\n<p>Azure Container Apps (ACA) dynamic sessions provide fast access to secure, sandboxed environments that have access to Azure Open AI (AOAI) via a code interpreter.\u00a0 ACA dynamic sessions offer strong isolation, access through a REST API, and are automatically deleted when no longer in use. The fast startup times achieved by maintaining a pool of ready sessions in ACA make it possible to allocate new sessions in milliseconds. dynamic sessions are also highly scalable, capable of running hundreds or thousands of sessions concurrently.<\/p>\n<h3>Code Interpreter and Java<\/h3>\n<p>Code interpreter sessions run code via code execution or uploaded files in a sandbox preinstalled with popular libraries, making them ideal for executing untrusted code provided by users or generated by large language models (LLMs).\u00a0 The default language for the container is Python, but most languages, including Java, are supported by the code interpreter.\u00a0 Learn more about <a href=\"https:\/\/learn.microsoft.com\/azure\/container-apps\/sessions\">ACA dynamic sessions on Microsoft Learn<\/a>.<\/p>\n<p>&nbsp;<\/p>\n<h3>POC Repo &#8211; <a href=\"https:\/\/github.com\/bbenz\/aca-dynamic-sessions\">aca-dynamic-sessions (github.com)<\/a><\/h3>\n<p>I&#8217;ve created a simple POC to explore how to use ACA dynamic sessions with Java via HTTP.\u00a0 \u00a0Stay tuned for a version that uses LangChain4J!\u00a0 in the meantime, here&#8217;s the <a href=\"https:\/\/github.com\/bbenz\/aca-dynamic-sessions\">simple POC on GitHub<\/a>.\u00a0 Check out the readme for full details on prerequisites and setup.<\/p>\n<p>For simplicity I&#8217;ve built the POC as a Spring Boot application that communicates with the dynamic sessions API, and covers the basic interactions with dynamic sessions, including executing code, plus uploading, listing and downloading files.<\/p>\n<p>Main Application Code\nThe main class, ACADynamicSessions, sets up the application and coordinates calls to other classes that perform various tasks. It retrieves variables defined in an application.properties file, then calls the getToken method to get an access token from Azure.<\/p>\n<p>The getToken method uses the Azure Identity library to get an access token. This token is used to authenticate the application&#8217;s requests to the &#8220;dynamicsessions&#8221; service. The token is requested for the scope &#8220;https:\/\/dynamicsessions.io\/.default&#8221;, which means it&#8217;s requested for all available permissions on the &#8220;dynamicsessions&#8221; service.<\/p>\n<p>The\u00a0<strong>getToken()<\/strong> Method is used to obtain an access token from Azure Active Directory (AAD) using the Azure Identity library.<\/p>\n<pre class=\"prettyprint language-java\"><code class=\"language-java\">private static String getToken() {\r\n        DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();\r\n        TokenRequestContext requestContext = new TokenRequestContext().addScopes(\"https:\/\/dynamicsessions.io\/.default\");\r\n        AccessToken token = credential.getToken(requestContext).block();\r\n        return token.getToken();\r\n    }<\/code><\/pre>\n<p>&nbsp;<\/p>\n<p>Here&#8217;s a breakdown of what this code does:<\/p>\n<ol>\n<li>Create a\u00a0<code>DefaultAzureCredential<\/code>object. This object represents a credential capable of providing an AAD token from multiple sources, such as environment variables, managed identity, or a local development service like Azure CLI or Visual Studio Code.<\/li>\n<li>Create a\u00a0<code>TokenRequestContext<\/code>\u00a0object and add a scope to it. The scope is a string that represents the resource and permissions your application is requesting access to. In this case, the scope is\u00a0&#8220;https:\/\/dynamicsessions.io\/.default&#8221;, which represents the default permissions for the dynamic sessions API.<\/li>\n<li>The\u00a0<code>block()<\/code>\u00a0method is called to requests the access token synchronously, meaning the method will not return until it has either successfully obtained a token or encountered an error.<\/li>\n<li>Return the actual string representation of the access token.<\/li>\n<\/ol>\n<p>This access token can then be used to authenticate requests to the dynamic sessions API.<\/p>\n<ul>\n<li>ACADynamicSessions also:<\/li>\n<li>Constructs several URLs using the retrieved configuration values and the access token.<\/li>\n<li>Calls methods from ExecuteCode, UploadFile, ListFiles, and DownloadFile classes, passing the constructed URLs and the access token to them.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<h3>Code Execution<\/h3>\n<p><code>ExecuteCode<\/code>\u00a0contains a single static method\u00a0<code>execute(String url, String token).<\/code><\/p>\n<p>The\u00a0<code>execute<\/code>\u00a0method is designed to send an HTTP POST request via the <code>OkHttpClient<\/code>\u00a0object to handle the HTTP request.to a specified URL with a JSON payload. The JSON payload contains properties for executing inline Python code <code>(print('Hello, world!')<\/code>) \u00a0synchronously.\u00a0 The client sends the request and gets a\u00a0<code>Response<\/code>\u00a0object. The response body is printed to the console.<\/p>\n<p>This code executes Python and returns a response that can be printed to the console, just to confirm that you have access to the Dynamic Session.\u00a0 The default language for the container is Python, but Java can then be executed via the code interpreter inside the Python container.<\/p>\n<pre class=\"prettyprint language-java\"><code class=\"language-java\"> String json = \"{\"\r\n        + \"\\\"properties\\\": {\"\r\n        + \"\\\"codeInputType\\\": \\\"inline\\\",\"\r\n        + \"\\\"executionType\\\": \\\"synchronous\\\",\"\r\n        + \"\\\"code\\\": \\\"print('Hello, world!')\\\"\"\r\n        +  \"}\"\r\n        +  \"}\";\r\n\r\n        RequestBody body = RequestBody.create(json, MediaType.parse(\"application\/json\"));\r\n        Request request = new Request.Builder()\r\n            .url(url)\r\n            .post(body)\r\n            .addHeader(\"Authorization\", \"Bearer \" + token)\r\n            .addHeader(\"Content-Type\", \"application\/json\")\r\n            .build();<\/code><\/pre>\n<p>&nbsp;<\/p>\n<h3>Working with Files<\/h3>\n<p>The <code>UploadFile <\/code>class is used to upload a file to dynamic sessions using the OkHttp library.\u00a0 It takes three parameters:\u00a0<code>url<\/code>\u00a0(the server URL to which the file will be uploaded),\u00a0token\u00a0(the authorization token for the server), and\u00a0<code>filename<\/code>\u00a0(the path of the file to be uploaded).\u00a0 A\u00a0<code>File<\/code>\u00a0object is created with the provided\u00a0<code>filename<\/code>.\u00a0 A\u00a0<code>RequestBody<\/code>\u00a0is created from the file and the media type is set to &#8220;application\/json&#8221; and a\u00a0<code>MultipartBody<\/code>\u00a0is created and set to the type\u00a0<code>FORM<\/code>. The file data is added to this body with the form data part name &#8220;file&#8221;.\u00a0 The response is captured in a\u00a0Response\u00a0object.<\/p>\n<pre class=\"prettyprint language-java\"><code class=\"language-java\">OkHttpClient client = new OkHttpClient();\r\n            \r\n        File file = new File(filename);\r\n        RequestBody fileBody = RequestBody.create(file, MediaType.parse(\"application\/json\"));\r\n        RequestBody body = new MultipartBody.Builder()\r\n            .setType(MultipartBody.FORM)\r\n            .addFormDataPart(\"file\", file.getName(), fileBody)\r\n            .build();\r\n\r\n        Request request = new Request.Builder()\r\n            .url(url)\r\n            .post(body)\r\n            .addHeader(\"Authorization\", \"Bearer \" + token)\r\n            .addHeader(\"Content-Type\", \"multipart\/form-data\")\r\n            .build();<\/code><\/pre>\n<p>The\u00a0<code>ListFiles<\/code>\u00a0class sends a GET request to a specified URL, parses the JSON response, and return a list of filenames.\u00a0 It takes two parameters:\u00a0<code>url\u00a0<\/code>(the server URL to which the file will be uploaded),\u00a0and <code>token<\/code>\u00a0(the authorization token for the server).\u00a0 \u00a0The response body is parsed as a JSON object, then a\u00a0<code>StringBuilder\u00a0<\/code>object is created to store the filenames.\u00a0 The code loops through each object in the &#8220;value&#8221; array in the JSON Object, then the string representation of the\u00a0<code>StringBuilder<\/code>\u00a0(which contains all filenames separated by commas) is returned.<\/p>\n<pre class=\"prettyprint language-java\"><code class=\"language-java\">        OkHttpClient client = new OkHttpClient();\r\n\r\n        Request request = new Request.Builder()\r\n            .url(url)\r\n            .get()\r\n            .addHeader(\"Authorization\", \"Bearer \" + token)\r\n            .build();\r\n\r\n        try (Response response = client.newCall(request).execute()) {\r\n            if (!response.isSuccessful()) {\r\n                throw new IOException(\"Unexpected code \" + response);\r\n            }\r\n\r\n            \/\/ Parse the response body as JSON\r\n            JSONObject json = new JSONObject(response.body().string());\r\n\r\n            \/\/ Create a StringBuilder to store the filenames\r\n            StringBuilder filenames = new StringBuilder();\r\n\r\n            \/\/ Get the \"value\" array from the JSON object\r\n            JSONArray valueArray = json.getJSONArray(\"value\");\r\n\r\n            \/\/ Loop through each object in the \"value\" array\r\n            for (int i = 0; i &lt; valueArray.length(); i++) {\r\n                \/\/ Get the current object\r\n                JSONObject currentObject = valueArray.getJSONObject(i);\r\n\r\n                \/\/ Get the \"properties\" object from the current object\r\n                JSONObject properties = currentObject.getJSONObject(\"properties\");\r\n\r\n                \/\/ Get the filename from the \"properties\" object\r\n                String filename = properties.getString(\"filename\");\r\n\r\n                \/\/ Append the filename to the StringBuilder\r\n                filenames.append(filename);\r\n\r\n                \/\/ If this is not the last filename, append a comma and a space\r\n                if (i &lt; valueArray.length() - 1) {\r\n                    filenames.append(\", \");\r\n                }\r\n            }\r\n\r\n            \/\/ Return the string representation of the StringBuilder\r\n            return filenames.toString();\r\n\r\n<\/code><\/pre>\n<p>The\u00a0<code>DownloadFile<\/code>\u00a0class is a simple example of how to download a file in Java using a GET request to a specified URL. It takes two parameters: a\u00a0<code>url<\/code>\u00a0from which to download the file, which is built from the ListFIles response, and a\u00a0<code>token<\/code>\u00a0for authorization.\u00a0 The body of the response is printed to the console, representing the content of the downloaded file.<\/p>\n<p>&nbsp;<\/p>\n<pre class=\"prettyprint language-java\"><code class=\"language-java\">OkHttpClient client = new OkHttpClient();\r\n\r\n        Request request = new Request.Builder()\r\n            .url(url)\r\n            .get()\r\n            .addHeader(\"Authorization\", \"Bearer \" + token)\r\n            .build();\r\n<\/code><\/pre>\n<p>&nbsp;<\/p>\n<h3>Summary<\/h3>\n<p>Let me know if this inspires you to use Azure Container Apps dynamic sessions to run Java code and why!\u00a0\u00a0Remember to check the <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/container-apps\/sessions\">overview of ACA dynamic sessions on Microsoft Learn<\/a> and the full POC repo on GitHub at <a href=\"https:\/\/aka.ms\/aca-dynamic-sessions\">https:\/\/aka.ms\/aca-dynamic-sessions<\/a>.\u00a0 And check back for a new version of this code using Langchain4J, coming soon!<\/p>\n<p>Happy Coding!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Have you ever needed to just run your Java code in an instant-on container in the cloud without the hassle of managing your own Kubernetes server?\u00a0 How about having access to Open AI code interpreter built-in to that container and billed on a consumption basis? About Azure Container Apps and dynamic sessions Azure Container Apps [&hellip;]<\/p>\n","protected":false},"author":110052,"featured_media":231149,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[816,1],"tags":[],"class_list":["post-231121","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure-container-apps","category-java"],"acf":[],"blog_post_summary":"<p>Have you ever needed to just run your Java code in an instant-on container in the cloud without the hassle of managing your own Kubernetes server?\u00a0 How about having access to Open AI code interpreter built-in to that container and billed on a consumption basis? About Azure Container Apps and dynamic sessions Azure Container Apps [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/posts\/231121","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/users\/110052"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/comments?post=231121"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/posts\/231121\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/media\/231149"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/media?parent=231121"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/categories?post=231121"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/tags?post=231121"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}