<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Ihor Didyk on Medium]]></title>
        <description><![CDATA[Stories by Ihor Didyk on Medium]]></description>
        <link>https://medium.com/@ididyk?source=rss-21d32cf45e7------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*A7mkxhoH5RsJwU0S.jpg</url>
            <title>Stories by Ihor Didyk on Medium</title>
            <link>https://medium.com/@ididyk?source=rss-21d32cf45e7------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 14:38:01 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@ididyk/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Part 2: Automating Kubernetes Manifests with Dekorate]]></title>
            <link>https://medium.com/@ididyk/part-2-automating-kubernetes-manifests-with-dekorate-02e85ca4e690?source=rss-21d32cf45e7------2</link>
            <guid isPermaLink="false">https://medium.com/p/02e85ca4e690</guid>
            <dc:creator><![CDATA[Ihor Didyk]]></dc:creator>
            <pubDate>Fri, 27 Dec 2024 11:28:03 GMT</pubDate>
            <atom:updated>2024-12-27T16:34:51.795Z</atom:updated>
            <content:encoded><![CDATA[<p><a href="https://kubernetes.io/"><strong>Kubernetes</strong></a> manifests are the backbone of application deployment in Kubernetes clusters.</p><p>In the <a href="https://medium.com/@ididyk/part-1-the-problem-with-kubernetes-manifests-ea4eea6cd61d"><strong>first part of this series</strong></a>, we explored the challenges Java developers face when manually creating Kubernetes manifests, such as the risk of errors, complexity, and time consumption.</p><p>In this second part, we dive into <a href="https://dekorate.io/"><strong>Dekorate</strong></a>, a powerful Java library that simplifies the process of generating Kubernetes manifests automatically, seamlessly integrating into your development workflow.</p><h3>Overview of Dekorate</h3><p>Dekorate is an open-source library that enables Java developers to generate Kubernetes manifests directly from code annotations. By building configurations into your application, you bridge the gap between application code and deployment configurations, reducing manual work and ensuring consistency.</p><h3>Key Features</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*A448oaprOcFnIxbRtuNxfQ.png" /></figure><h3>Design of Dekorate</h3><p>Dekorate is built on a modular design to streamline Kubernetes resource generation. The core design revolves around annotation processors, crucial in interpreting annotations and generating configurations.</p><ol><li><strong>Annotation Processors</strong>: Dekorate includes multiple annotation processors, each responsible for generating Kubernetes resources for specific annotations. The compiler invokes these processors at least twice during the build process when it detects matching annotations in the code.</li><li><strong>Processing Flow</strong>:<br> — During each invocation, the annotation processor collects information from the annotated classes.<br> — The final invocation signals the end of the processing stage when the collected data is passed to configuration handlers.</li><li><strong>Configuration Handlers</strong>: Once the processing is complete, handlers receive the assembled configuration objects from the annotation processors. These handlers modify or create models based on the provided configuration.</li><li><strong>Model Serialization</strong>: The resulting models are serialized into JSON or YAML files and stored on disk. These files include Deployment manifests, Service configurations, and other Kubernetes resources, ready for deployment.</li></ol><p>This modular design ensures that Dekorate is flexible, extensible, and capable of handling a wide range of Kubernetes configurations.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XSgPeCmzjgMMZL4pyCu8OA.png" /><figcaption>Source of diagram: <a href="https://github.com/dekorateio/dekorate/blob/main/assets/design.md">https://github.com/dekorateio/dekorate/blob/main/assets/design.md</a></figcaption></figure><blockquote>It’s crucial to thoroughly understand the available configuration options to ensure seamless operation and prevent potential errors. You can refer to the github repo with <a href="https://github.com/dekorateio/dekorate/blob/main/assets/config.md">Dekorate Configuration Documentation</a> for detailed guidance.</blockquote><h3>Setting Up Dekorate in Your Project</h3><p>Let’s explore how to integrate Dekorate into your Java project using Maven. Gradle users can follow a similar setup with minor adjustments.</p><h4>1. Adding Dependencies</h4><p>To begin, add Dekorate dependencies to your pom.xml file:</p><pre>    &lt;dependencies&gt;<br>        &lt;dependency&gt;<br>            &lt;groupId&gt;io.dekorate&lt;/groupId&gt;<br>            &lt;artifactId&gt;kubernetes-annotations&lt;/artifactId&gt;<br>            &lt;version&gt;4.1.4&lt;/version&gt;<br>        &lt;/dependency&gt;<br><br>        &lt;dependency&gt;<br>            &lt;groupId&gt;io.dekorate&lt;/groupId&gt;<br>            &lt;artifactId&gt;docker-annotations&lt;/artifactId&gt;<br>            &lt;version&gt;4.1.4&lt;/version&gt;<br>        &lt;/dependency&gt;<br><br>        &lt;dependency&gt;<br>            &lt;groupId&gt;io.dekorate&lt;/groupId&gt;<br>            &lt;artifactId&gt;helm-annotations&lt;/artifactId&gt;<br>            &lt;version&gt;4.1.4&lt;/version&gt;<br>        &lt;/dependency&gt;<br><br>        &lt;dependency&gt;<br>            &lt;groupId&gt;io.dekorate&lt;/groupId&gt;<br>            &lt;artifactId&gt;dekorate-spring-boot&lt;/artifactId&gt;<br>            &lt;version&gt;4.1.4&lt;/version&gt;<br>        &lt;/dependency&gt;<br><br>        &lt;!--Transitive dependencies to fix vulnerability of io.dekorate:dekorate-spring-boot:4.1.4--&gt;<br>        &lt;!-- GHSA-w33c-445m-f8w7 (5.9) Transitive Okio Signed to Unsigned Conversion Error vulnerability --&gt;<br>        &lt;dependency&gt;<br>            &lt;groupId&gt;org.apache.commons&lt;/groupId&gt;<br>            &lt;artifactId&gt;commons-compress&lt;/artifactId&gt;<br>            &lt;version&gt;1.27.1&lt;/version&gt;<br>        &lt;/dependency&gt;<br>        &lt;dependency&gt;<br>            &lt;groupId&gt;ch.qos.logback&lt;/groupId&gt;<br>            &lt;artifactId&gt;logback-core&lt;/artifactId&gt;<br>            &lt;version&gt;1.5.15&lt;/version&gt;<br>        &lt;/dependency&gt;<br>        &lt;dependency&gt;<br>            &lt;groupId&gt;com.squareup.okio&lt;/groupId&gt;<br>            &lt;artifactId&gt;okio&lt;/artifactId&gt;<br>            &lt;version&gt;3.9.0&lt;/version&gt;<br>        &lt;/dependency&gt;<br><br>    &lt;/dependencies&gt;</pre><p>For Gradle projects, include the following in your build.gradle file:</p><pre>dependencies {<br>    // Dekorate dependencies<br>    implementation &#39;io.dekorate:kubernetes-annotations:4.1.4&#39;<br>    implementation &#39;io.dekorate:docker-annotations:4.1.4&#39;<br>    implementation &#39;io.dekorate:helm-annotations:4.1.4&#39;<br>    implementation &#39;io.dekorate:dekorate-spring-boot:4.1.4&#39;<br><br>    // Fix vulnerabilities for dekorate-spring-boot transitive dependencies<br>    implementation &#39;org.apache.commons:commons-compress:1.27.1&#39;<br>    implementation &#39;ch.qos.logback:logback-core:1.5.15&#39;<br>    implementation &#39;com.squareup.okio:okio:3.9.0&#39;<br>}</pre><p>Or .gradle.kts (Kotlin DSL):</p><pre>dependencies {<br>    // Dekorate dependencies<br>    implementation(&quot;io.dekorate:kubernetes-annotations:4.1.4&quot;)<br>    implementation(&quot;io.dekorate:docker-annotations:4.1.4&quot;)<br>    implementation(&quot;io.dekorate:helm-annotations:4.1.4&quot;)<br>    implementation(&quot;io.dekorate:dekorate-spring-boot:4.1.4&quot;)<br><br>    // Fix vulnerabilities for dekorate-spring-boot transitive dependencies<br>    implementation(&quot;org.apache.commons:commons-compress:1.27.1&quot;)<br>    implementation(&quot;ch.qos.logback:logback-core:1.5.15&quot;)<br>    implementation(&quot;com.squareup.okio:okio:3.9.0&quot;)<br>}</pre><h4>2. Applying Annotations</h4><p>With Dekorate, you define Kubernetes configurations using annotations. For example, to generate a Kubernetes Deployment, Service, Ingress, configure helm chart, and docker build, you should create a @Configuration annotated class :</p><pre>package com.ih0rd.sandbox.config;<br><br>import io.dekorate.annotation.Dekorate;<br>import io.dekorate.docker.annotation.DockerBuild;<br>import io.dekorate.helm.annotation.HelmChart;<br>import io.dekorate.kubernetes.annotation.*;<br>import io.dekorate.kubernetes.config.DeploymentStrategy;<br>import org.springframework.boot.autoconfigure.SpringBootApplication;<br>import org.springframework.context.annotation.Configuration;<br><br>@SpringBootApplication<br>@KubernetesApplication(<br>        ingress = @Ingress(<br>                expose = true,<br>                ingressClassName = &quot;nginx&quot;,<br>                host = &quot;medium-article-part2.local&quot;,<br>                rules = {<br>                        @IngressRule(<br>                                host = &quot;medium-article-part2.local&quot;,<br>                                serviceName = &quot;medium-article-part2&quot;,<br>                                servicePortName = &quot;8080&quot;<br>                        )<br>                },<br>                tlsSecretName = &quot;medium-article-part2-tls-secret&quot;,<br>                tlsHosts = {&quot;medium-article-part2.local&quot;}<br>        ),<br>        replicas = 2,<br>        ports = {@Port(name = &quot;http&quot;, containerPort = 8080)},<br>        labels = {@Label(key = &quot;article&quot;, value = &quot;medium-part2-code&quot;)},<br>        livenessProbe = @Probe(<br>                httpActionPath = &quot;/health/liveness&quot;,<br>                initialDelaySeconds = 5,<br>                timeoutSeconds = 3,<br>                failureThreshold = 10<br>        ),<br>        readinessProbe = @Probe(<br>                httpActionPath = &quot;/health/readiness&quot;,<br>                initialDelaySeconds = 5,<br>                timeoutSeconds = 3,<br>                failureThreshold = 10<br>        ),<br>        requestResources = @ResourceRequirements(<br>                memory = &quot;64Mi&quot;,<br>                cpu = &quot;1m&quot;<br>        ),<br>        limitResources = @ResourceRequirements(<br>                memory = &quot;64Mi&quot;,<br>                cpu = &quot;1m&quot;<br>        ),<br>        rollingUpdate = @RollingUpdate(maxSurge = &quot;50%&quot;, maxUnavailable = &quot;50%&quot;),<br>        deploymentStrategy = DeploymentStrategy.RollingUpdate,<br>        serviceType = ServiceType.LoadBalancer // Add LoadBalancer for work with Ingress<br>)<br>@DockerBuild(image = &quot;custom-image:latest&quot;)<br>@HelmChart(name = &quot;custom-helm-chart&quot;)<br>@Configuration // Just to register for Spring Boot app<br>public class K8sDekorateAnnotationsConfiguration {<br>}</pre><h4>3. Generating Manifests</h4><p>Once the annotations are in place, build your project to generate the manifests. You can run Maven or Gradle or their wrappers (I prefer to use the wrapper’s approach):</p><pre>./mvnw clean package<br><br># or<br><br>./gradlew build</pre><p>Dekorate will create the Kubernetes YAML(and JSON) files under the target/classes/META-INF/dekorate directory (for Maven) or build/classes/java/main/META-INF/dekorate directory (for Gradle).</p><p>Docker images and Helm charts will also be generated in their respective build directories.</p><pre>├── helm<br>│   └── kubernetes<br>│       └── custom-helm-chart<br>│           ├── Chart.yaml<br>│           ├── README.md<br>│           ├── charts<br>│           ├── templates<br>│           │   ├── NOTES.txt<br>│           │   ├── deployment.yaml<br>│           │   └── service.yaml<br>│           ├── values.schema.json<br>│           └── values.yaml<br>├── kubernetes.json<br>└── kubernetes.yml</pre><h4>4. Reviewing Generated Manifests</h4><p>Inspect the generated files to ensure they match your deployment requirements. For instance, a kubernetes.yml might look like this:</p><pre>---<br>apiVersion: apps/v1<br>kind: Deployment<br>metadata:<br>  annotations:<br>    app.dekorate.io/vcs-url: git@github.com:ih0r-d/examples-for-medium-articles.git<br>    app.dekorate.io/commit-id: 0bd629113c344c4b8948f239d8929fe31a4f87d6<br>  labels:<br>    app.kubernetes.io/name: medium-articles-k8s-generation-sandbox<br>    app.kubernetes.io/version: 0.0.1-SNAPSHOT<br>    article: medium-part2-code<br>  name: medium-articles-k8s-generation-sandbox<br>spec:<br>  replicas: 2<br>  selector:<br>    matchLabels:<br>      app.kubernetes.io/name: medium-articles-k8s-generation-sandbox<br>      app.kubernetes.io/version: 0.0.1-SNAPSHOT<br>      article: medium-part2-code<br>  strategy:<br>    rollingUpdate:<br>      maxSurge: 50%<br>      maxUnavailable: 50%<br>    type: RollingUpdate<br>  template:<br>    metadata:<br>      annotations:<br>        app.dekorate.io/vcs-url: git@github.com:ih0r-d/examples-for-medium-articles.git<br>        app.dekorate.io/commit-id: 0bd629113c344c4b8948f239d8929fe31a4f87d6<br>      labels:<br>        app.kubernetes.io/name: medium-articles-k8s-generation-sandbox<br>        app.kubernetes.io/version: 0.0.1-SNAPSHOT<br>        article: medium-part2-code<br>    spec:<br>      containers:<br>        - env:<br>            - name: KUBERNETES_NAMESPACE<br>              valueFrom:<br>                fieldRef:<br>                  fieldPath: metadata.namespace<br>          image: custom-image:latest<br>          imagePullPolicy: IfNotPresent<br>          livenessProbe:<br>            failureThreshold: 10<br>            httpGet:<br>              path: /health/liveness<br>              port: 8080<br>              scheme: HTTP<br>            initialDelaySeconds: 5<br>            periodSeconds: 30<br>            successThreshold: 1<br>            timeoutSeconds: 3<br>          name: medium-articles-k8s-generation-sandbox<br>          ports:<br>            - containerPort: 8080<br>              name: http<br>              protocol: TCP<br>          readinessProbe:<br>            failureThreshold: 10<br>            httpGet:<br>              path: /health/readiness<br>              port: 8080<br>              scheme: HTTP<br>            initialDelaySeconds: 5<br>            periodSeconds: 30<br>            successThreshold: 1<br>            timeoutSeconds: 3<br>          resources:<br>            limits:<br>              cpu: 1m<br>              memory: 64Mi<br>            requests:<br>              cpu: 1m<br>              memory: 64Mi<br>---<br>apiVersion: networking.k8s.io/v1<br>kind: Ingress<br>metadata:<br>  annotations:<br>    app.dekorate.io/vcs-url: git@github.com:ih0r-d/examples-for-medium-articles.git<br>    app.dekorate.io/commit-id: 0bd629113c344c4b8948f239d8929fe31a4f87d6<br>  labels:<br>    app.kubernetes.io/name: medium-articles-k8s-generation-sandbox<br>    app.kubernetes.io/version: 0.0.1-SNAPSHOT<br>    article: medium-part2-code<br>  name: medium-articles-k8s-generation-sandbox<br>spec:<br>  ingressClassName: nginx<br>  rules:<br>    - host: medium-article-part2.local<br>      http:<br>        paths:<br>          - backend:<br>              service:<br>                name: medium-article-part2<br>                port:<br>                  name: &quot;8080&quot;<br>            path: /<br>            pathType: Prefix<br>  tls:<br>    - hosts:<br>        - medium-article-part2.local<br>      secretName: medium-article-part2-tls-secret<br>---<br>apiVersion: v1<br>kind: Service<br>metadata:<br>  annotations:<br>    app.dekorate.io/vcs-url: git@github.com:ih0r-d/examples-for-medium-articles.git<br>    app.dekorate.io/commit-id: 0bd629113c344c4b8948f239d8929fe31a4f87d6<br>  labels:<br>    app.kubernetes.io/name: medium-articles-k8s-generation-sandbox<br>    app.kubernetes.io/version: 0.0.1-SNAPSHOT<br>    article: medium-part2-code<br>  name: medium-articles-k8s-generation-sandbox<br>spec:<br>  ports:<br>    - name: http<br>      port: 80<br>      protocol: TCP<br>      targetPort: 8080<br>  selector:<br>    app.kubernetes.io/name: medium-articles-k8s-generation-sandbox<br>    app.kubernetes.io/version: 0.0.1-SNAPSHOT<br>    article: medium-part2-code<br>  type: LoadBalancer</pre><p>And, let’s imagine how Dekorate integrates into your project, consider the following workflow:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nbLuAP0ZaM89FDdjq2lHbw.png" /></figure><h4>Advantages of Using Dekorate</h4><ul><li><strong>Simplified Configuration:</strong> <br>Eliminates the need for hand-written YAML files.</li><li><strong>Consistency: <br></strong>Reduces the risk of configuration drift between code and deployment settings.</li><li><strong>Developer Productivity:</strong> <br>Speeds up the Kubernetes deployment process, allowing developers to focus on coding.</li><li><strong>Advanced Features:</strong> <br>Supports CRDs, ConfigMaps, Secrets, Ingress, Docker images, and Helm charts.</li><li><strong>Multi-Platform Support:</strong> <br>Enables deployment to Kubernetes, OpenShift, Knative, and Helm seamlessly.</li><li><strong>Docker and Helm Integration:</strong> <br>Automates the generation of Docker images and Helm charts, streamlining complex deployments.</li><li><strong>Testing Support:</strong> <br>Ensures Kubernetes configurations are tested and validated during development.</li></ul><p>Dekorate has a lot of advantages, but for me, the more interesting is testing support, do you ask me what I mean? Let’s see an example of tests for generated manifests.</p><p><strong>Tests folder structure:</strong></p><pre>src/test/java/com/ih0rd/sandbox/<br>├── DekorateK8sConfigTest.java  // Main test class for verifying Dekorate-generated Kubernetes resources<br>└── SharedUtils.java            // Utility class for loading and querying Kubernetes resources in tests</pre><ul><li><strong>DekorateK8sConfigTest.java:</strong><br> — Contains integration tests to validate that Dekorate annotations correctly generate Kubernetes resources (e.g., Deployment, Ingress, Service).<br> — Includes methods to check the structure and properties of the generated resources.</li></ul><pre>package com.ih0rd.sandbox;<br><br>import io.dekorate.helm.model.Chart;<br>import io.fabric8.kubernetes.api.model.*;<br>import io.fabric8.kubernetes.api.model.apps.Deployment;<br>import io.fabric8.kubernetes.api.model.networking.v1.Ingress;<br>import org.junit.jupiter.api.BeforeAll;<br>import org.junit.jupiter.api.Test;<br><br><br>import java.io.IOException;<br><br>import static org.junit.jupiter.api.Assertions.*;<br><br>public class DekorateK8sConfigTest {<br><br>    private static KubernetesList K8S_RESOURCES;<br>    private static final String EXPECTED_DEPLOYMENT_NAME = &quot;medium-articles-k8s-generation-sandbox&quot;;<br>    private static final String EXPECTED_IMAGE = &quot;custom-image:latest&quot;;<br>    private static final String EXPECTED_INGRESS_HOST = &quot;medium-article-part2.local&quot;;<br>    private static final String EXPECTED_TLS_SECRET = &quot;medium-article-part2-tls-secret&quot;;<br>    private static final String EXPECTED_HELM_CHART_NAME = &quot;custom-helm-chart&quot;;<br><br>    @BeforeAll<br>    static void setupAll() {<br>        K8S_RESOURCES = SharedUtils.loadKubernetesResources();<br>    }<br><br>    @Test<br>    public void shouldGenerateDeployment() {<br>        assertNotNull(K8S_RESOURCES, &quot;Kubernetes resources should not be null&quot;);<br>        Deployment deployment = SharedUtils.findFirst(Deployment.class);<br>        assertNotNull(deployment, &quot;Deployment resource should exist&quot;);<br>        assertEquals(EXPECTED_DEPLOYMENT_NAME, deployment.getMetadata().getName(), &quot;Deployment name mismatch&quot;);<br><br>        final AnyType expectedRollingUpdateMaxValue = new AnyType(&quot;50%&quot;);<br>        // Validate replicas and strategy<br>        assertEquals(2, deployment.getSpec().getReplicas(), &quot;Replica count mismatch&quot;);<br>        assertEquals(&quot;RollingUpdate&quot;, deployment.getSpec().getStrategy().getType(), &quot;Deployment strategy mismatch&quot;);<br>        assertEquals(expectedRollingUpdateMaxValue, deployment.getSpec().getStrategy().getRollingUpdate().getMaxSurge(), &quot;MaxSurge mismatch&quot;);<br>        assertEquals(expectedRollingUpdateMaxValue, deployment.getSpec().getStrategy().getRollingUpdate().getMaxUnavailable(), &quot;MaxUnavailable mismatch&quot;);<br>    }<br><br>    @Test<br>    public void shouldSetContainerImage() {<br>        Deployment deployment = SharedUtils.findFirst(Deployment.class);<br>        assertNotNull(deployment, &quot;Deployment resource should exist&quot;);<br><br>        Container container = deployment.getSpec().getTemplate().getSpec().getContainers().getFirst();<br>        assertNotNull(container, &quot;Container should exist in Deployment&quot;);<br>        assertEquals(EXPECTED_IMAGE, container.getImage(), &quot;Container image mismatch&quot;);<br>    }<br><br><br>    @Test<br>    public void shouldExposeServiceAsLoadBalancer() {<br>        Service service = SharedUtils.findFirst(Service.class);<br>        assertNotNull(service, &quot;Service resource should exist&quot;);<br>        assertEquals(&quot;LoadBalancer&quot;, service.getSpec().getType(), &quot;Service type mismatch&quot;);<br>    }<br><br>    @Test<br>    public void shouldGenerateHelmChart() throws IOException {<br>        Chart chart = SharedUtils.read(&quot;META-INF/dekorate/helm/kubernetes/&quot; + EXPECTED_HELM_CHART_NAME + &quot;/Chart.yaml&quot;, Chart.class);<br>        assertNotNull(chart, &quot;Helm chart should exist&quot;);<br>        assertEquals(EXPECTED_HELM_CHART_NAME, chart.getName(), &quot;Helm chart name mismatch&quot;);<br>    }<br><br>    @Test<br>    public void shouldGenerateIngress() {<br>        Ingress ingress = SharedUtils.findFirst(Ingress.class);<br>        assertNotNull(ingress, &quot;Ingress resource should exist&quot;);<br>        assertEquals(EXPECTED_INGRESS_HOST, ingress.getSpec().getRules().getFirst().getHost(), &quot;Ingress host mismatch&quot;);<br><br>        // Validate TLS<br>        assertEquals(EXPECTED_TLS_SECRET, ingress.getSpec().getTls().getFirst().getSecretName(), &quot;TLS secret name mismatch&quot;);<br>        assertTrue(ingress.getSpec().getTls().getFirst().getHosts().contains(EXPECTED_INGRESS_HOST), &quot;TLS host mismatch&quot;);<br>    }<br>}</pre><ul><li><strong>SharedUtils.java:</strong><br> — Provides helper methods to load Kubernetes YAML files generated by Dekorate.<br> — Includes utility methods such as findFirst for locating specific resource types within the Kubernetes manifest.</li></ul><pre>package com.ih0rd.sandbox;<br><br>import io.dekorate.utils.Serialization;<br>import io.fabric8.kubernetes.api.model.HasMetadata;<br>import io.fabric8.kubernetes.api.model.KubernetesList;<br><br>import java.io.IOException;<br>import java.util.Objects;<br><br>import static org.junit.jupiter.api.Assertions.assertNotNull;<br><br>public class SharedUtils {<br><br>    private static final String K8S_MANIFEST = &quot;META-INF/dekorate/kubernetes.yml&quot;;<br><br>    public static KubernetesList loadKubernetesResources() {<br>        return Serialization.unmarshalAsList(Objects.requireNonNull(SharedUtils.class.getClassLoader().getResourceAsStream(K8S_MANIFEST)));<br>    }<br><br>    @SuppressWarnings(&quot;unchecked&quot;)<br>    public static &lt;T extends HasMetadata&gt; T findFirst(Class&lt;T&gt; clazz) {<br>        KubernetesList list = loadKubernetesResources();<br>        assertNotNull(list);<br><br>        return (T) list.getItems().stream()<br>                .filter(clazz::isInstance)<br>                .findFirst()<br>                .orElseThrow(() -&gt; new IllegalStateException(&quot;Resource of type &quot; + clazz.getName() + &quot; not found&quot;));<br>    }<br><br>    public static &lt;T&gt; T read(String path, Class&lt;T&gt; clazz) throws IOException {<br>        return Serialization.yamlMapper().readValue(SharedUtils.class.getClassLoader()<br>                .getResourceAsStream(path), clazz);<br>    }<br><br>}</pre><p>After building a project, all tests run and passed</p><pre>[INFO] --- maven-surefire-plugin:3.5.2:test (default-test) @ medium-articles-k8s-generation-sandbox ---<br>[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider<br>[INFO] <br>[INFO] -------------------------------------------------------<br>[INFO]  T E S T S<br>[INFO] -------------------------------------------------------<br>[INFO] Running com.ih0rd.sandbox.DekorateK8sConfigTest<br>[INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.522 s -- in com.ih0rd.sandbox.DekorateK8sConfigTest<br>[INFO] <br>[INFO] Results:<br>[INFO] <br>[INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0<br>[INFO] <br>[INFO] <br>[INFO] --- maven-jar-plugin:3.4.2:jar (default-jar) @ medium-articles-k8s-generation-sandbox ---<br>[INFO] Building jar: /Users/ihordidyk/Documents/personal/projects/medium-articles-k8s-generation-sandbox/target/medium-articles-k8s-generation-sandbox-0.0.1-SNAPSHOT.jar<br>[INFO] <br>[INFO] --- spring-boot-maven-plugin:3.4.1:repackage (repackage) @ medium-articles-k8s-generation-sandbox ---<br>[INFO] Replacing main artifact /Users/ihordidyk/Documents/personal/projects/medium-articles-k8s-generation-sandbox/target/medium-articles-k8s-generation-sandbox-0.0.1-SNAPSHOT.jar with repackaged archive, adding nested dependencies in BOOT-INF/.<br>[INFO] The original artifact has been renamed to /Users/ihordidyk/Documents/personal/projects/medium-articles-k8s-generation-sandbox/target/medium-articles-k8s-generation-sandbox-0.0.1-SNAPSHOT.jar.original<br>[INFO] ------------------------------------------------------------------------<br>[INFO] BUILD SUCCESS<br>[INFO] ------------------------------------------------------------------------<br>[INFO] Total time:  3.917 s<br>[INFO] Finished at: 2024-12-26T19:21:59+02:00<br>[INFO] ------------------------------------------------------------------------</pre><blockquote>For a more detailed example, see the code on <a href="https://github.com/ih0r-d/examples-for-medium-articles/tree/part2-article-dekorate-example">GitHub</a></blockquote><h4>Limitations of Dekorate</h4><p>While Dekorate offers a host of advantages, it also comes with certain limitations that developers should be aware of:</p><ul><li><strong>Learning Curve: </strong><br>The extensive annotation-based configuration requires developers to familiarize themselves with numerous annotations, which can be challenging for beginners.</li><li><strong>Customization Constraints:</strong> <br>While annotations are a powerful tool, they may not cover all edge cases or provide the flexibility that handwritten YAML files can offer. Currently, annotations do not support <a href="https://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/expressions.html">Spring Expression Language (SpEL)</a>, meaning values cannot be dynamically retrieved from application.properties or similar configuration files, resulting in hard-coded values.<br>However, you can combine Dekorate annotations with Spring <a href="https://docs.spring.io/spring-framework/reference/core/beans/annotation-config/value-annotations.html">@Value</a> annotations for more flexible configurations. <br>This approach allows you to externalize configuration values while using annotation-based manifest generation.</li><li><strong>Dependency Management: </strong><br>The reliance on multiple dependencies might lead to versioning issues or conflicts, especially in large projects.</li><li><strong>Limited Ecosystem for Testing: </strong><br>Although integration testing is supported, the ecosystem for advanced testing scenarios (e.g., simulating failures) is still evolving.</li><li><strong>Tight Coupling with Code:</strong> <br>Embedding Kubernetes configurations directly in the application code can lead to tighter coupling, making the configuration less reusable across projects.</li><li><strong>Build Tool Dependence: </strong><br>While Dekorate supports Maven and Gradle, using less common build tools might require additional configuration effort.</li></ul><p>Despite these limitations, Dekorate remains a valuable tool for Java developers seeking to streamline Kubernetes manifest generation and deployment.</p><h3>Next steps</h3><p>Dekorate has proven to be a great tool for automating Kubernetes manifests, Docker images, and Helm diagrams, as seen in this article. In <a href="https://medium.com/@ididyk/part-1-the-problem-with-kubernetes-manifests-ea4eea6cd61d"><strong>Part 1: The Problem with Kubernetes Manifests for Java Developers</strong></a>, we discussed common problems that Java developers face when working with Kubernetes manifests, including the difficulty of writing <strong>YAML</strong> files by hand and managing them. <br>Dekorate solves many of these problems, but is it the perfect solution?</p><p>In the next part of this series, we will dive deeper into <a href="https://eclipse.dev/jkube/"><strong>Eclipse JKube</strong></a>, a tool that offers more than just manifest generation. <br>Does JKube simplify the process even more? <br>Can it provide a more integrated experience for Java developers?</p><p>We’ll compare it with Dekorate, explore its strengths and weaknesses, and see which tool is better suited for different use cases.</p><p>Stay tuned to see how we take this comparison to the next level and explore the full potential of Kubernetes integration for Java applications!</p><h3>Resources</h3><p>Here are some helpful links related to Dekorate and Kubernetes:</p><ul><li><a href="https://dekorate.io/"><strong>Dekorate Official Documentation</strong></a>— Learn more about Dekorate’s features and configurations.</li><li><a href="https://github.com/dekorateio/dekorate"><strong>GitHub Repository for Dekorate</strong></a> — Access the source code and examples.</li><li><a href="https://github.com/fabric8io/kubernetes-client"><strong>Fabric8 Kubernetes Client</strong></a> — The library Dekorate uses for Kubernetes resource generation.</li><li><a href="https://helm.sh/docs/"><strong>Helm Documentation</strong></a> — Learn about Helm charts and their usage.</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=02e85ca4e690" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Part 1: The Problem with Kubernetes Manifests for Java Developers]]></title>
            <link>https://medium.com/@ididyk/part-1-the-problem-with-kubernetes-manifests-ea4eea6cd61d?source=rss-21d32cf45e7------2</link>
            <guid isPermaLink="false">https://medium.com/p/ea4eea6cd61d</guid>
            <dc:creator><![CDATA[Ihor Didyk]]></dc:creator>
            <pubDate>Thu, 19 Dec 2024 20:50:24 GMT</pubDate>
            <atom:updated>2024-12-20T09:09:03.289Z</atom:updated>
            <content:encoded><![CDATA[<p><a href="https://kubernetes.io/"><strong>Kubernetes</strong></a> has become a universal solution for deploying and managing containerized applications, offering scalability, fault tolerance, and flexibility. At the heart of this system are manifests, <a href="https://yaml.org/"><strong>YAML</strong></a> files that describe the desired state of resources such as Deployments, Services, and ConfigMaps. Despite their importance, these files often pose challenges for developers, especially when they are created and maintained manually.</p><p>For Java developers, balancing the complexity of Kubernetes’ manifestations with the intricacies of application logic can be overwhelming.</p><p>This article is the first part of a series on <strong>“Creating Kubernetes Manifests”</strong> that discusses how Java developers can simplify and automate the creation of Kubernetes manifests.</p><h4>Let’s dive into the <strong>agenda</strong> and explore how Kubernetes manifests play a crucial role in efficiently deploying Java applications.</h4><ul><li>Introduction to Kubernetes manifests and their role.</li><li>Types of Kubernetes manifests.</li><li>Challenges of manual YAML creation (errors, complexity, time).</li></ul><h4>Short introduction of k8s manifests and their role.</h4><p>Let’s start from <strong>k8s lifecycle:</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nyr0vQNn36hJ57h3znK6NA.png" /><figcaption>k8s lifecycle workflow</figcaption></figure><p><strong>Lifecycle explanation:</strong></p><ol><li>Developers write a manifest (e.g., Deployment, Service).</li><li>The manifest is applied to the cluster (kubectl apply).</li><li>Kubernetes’ API server processes the manifest and passes the instructions to the scheduler and controller manager.</li><li>Kubernetes ensures the desired state is achieved and maintains it over time.</li></ol><p><strong>For this guide, we’ll focus on Kubernetes manifests</strong> — the backbone of deploying applications in Kubernetes. They are YAML or JSON files that describe the desired state of an application, allowing Kubernetes to manage the deployment, scaling, and configuration of your workloads automatically. For Java developers, Kubernetes manifests provide a declarative way to ensure their applications run reliably in production environments.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xG4LeHqIpvjtCrEq9Mjr_g.png" /><figcaption>k8s manifests</figcaption></figure><h4>Why Manifests Are of Crucial Importance?</h4><p>Manifests serve as the authoritative source of truth for the configuration and deployment of your application. They enable you to:</p><ul><li>Define the number of application replicas to run.</li><li>Specify container images, environment variables, and resource limits.</li><li>Expose your application to the network via Services or Ingress.</li><li>Manage application secrets and configuration using ConfigMaps or Secrets.</li></ul><p>Without manifests, deploying and scaling applications in Kubernetes would become a disorganized and error-prone process. However, manually writing and maintaining these files can be challenging, particularly as the complexity of your application increases.</p><h4>The Challenges of Manual Manifest Management</h4><ol><li><strong>Complexity</strong>: Even for a simple application, multiple manifest files may be required. For instance, a basic microservice typically needs a Deployment, a Service, and potentially a ConfigMap or Secret.</li><li><strong>Error-Prone</strong>: YAML syntax is notoriously unforgiving. A misplaced space or indentation can break your deployment.</li><li><strong>Time-Consuming</strong>: Updating manifests manually for every version change or configuration adjustment can consume significant developer time, diverting focus from more critical tasks.</li></ol><p>Below are the <strong>main Kubernetes manifests</strong> for deploying typical Java applications, along with examples, workflows, and brief explanations:</p><blockquote>A <a href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/"><strong>Deployment</strong></a> defines how your application runs, including the number of replicas and the container details. It ensures high availability by maintaining the desired number of application instances, handling updates and scaling seamlessly.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0hBDaeIlif53SB5nB6zZzg.png" /><figcaption>Deployment’s Workflow</figcaption></figure><pre>apiVersion: apps/v1<br>kind: Deployment<br>metadata:<br>  name: java-app-deployment<br>spec:<br>  replicas: 3<br>  selector:<br>    matchLabels:<br>      app: java-app<br>  template:<br>    metadata:<br>      labels:<br>        app: java-app<br>    spec:<br>      containers:<br>        - name: java-app-container<br>          image: java-app:1.0.0<br>          ports:<br>            - containerPort: 8080</pre><blockquote>A <a href="https://kubernetes.io/docs/concepts/services-networking/service/"><strong>Service</strong></a> exposes your application to other components or external users, allowing consistent access regardless of Pod IP changes. It serves as a reliable communication endpoint, abstracting the details of individual Pods and ensuring consistent traffic routing to the application, even when Pods are replaced or restarted.</blockquote><pre>apiVersion: v1<br>kind: Service<br>metadata:<br>  name: java-app-service<br>spec:<br>  selector:<br>    app: java-app<br>  ports:<br>    - protocol: TCP<br>      port: 80<br>      targetPort: 8080<br>  type: ClusterIP</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*U7XnpAwB924-ZMXJTy0OGg.png" /><figcaption>Service’s Workflow</figcaption></figure><blockquote>A <a href="https://kubernetes.io/docs/concepts/configuration/configmap/"><strong>ConfigMap</strong></a> stores configuration data (like env variables) separately from the application, making it easier to update without redeploying the app. By decoupling configuration from the application, ConfigMaps make it easy to adapt settings for different environments or deployments.</blockquote><pre>apiVersion: v1<br>kind: ConfigMap<br>metadata:<br>  name: java-app-config<br>data:<br>  APP_NAME: &quot;My Java App&quot;<br>  APP_VERSION: &quot;1.0.0&quot;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DsSBB86uM8QsJU7eZexvdw.png" /><figcaption>ConfigMap’s Workflow</figcaption></figure><blockquote><a href="https://kubernetes.io/docs/concepts/services-networking/ingress/"><strong>Ingress</strong></a> provides external access to your application via HTTP/HTTPS, often with load balancing and SSL termination, handles external HTTP/HTTPS traffic and routes it to the correct Service, enabling seamless external access to your Java app.</blockquote><pre>apiVersion: networking.k8s.io/v1<br>kind: Ingress<br>metadata:<br>  name: java-app-ingress<br>spec:<br>  rules:<br>    - host: java-app.local<br>      http:<br>        paths:<br>          - path: /<br>            pathType: Prefix<br>            backend:<br>              service:<br>                name: java-app-service<br>                port:<br>                  number: 80</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iYKO4llMWHiYwWjwrIPNdg.png" /><figcaption>Ingres’s workflow</figcaption></figure><blockquote>A <a href="https://kubernetes.io/docs/concepts/configuration/secret/"><strong>Secret</strong></a> securely stores sensitive data like API keys or database credentials, protecting them from being exposed in plain text, it provides a secure way to manage sensitive data without hardcoding it into your application or configuration files.</blockquote><pre>apiVersion: v1<br>kind: Secret<br>metadata:<br>  name: java-app-secret<br>type: Opaque<br>data:<br>  DB_PASSWORD: cGFzc3dvcmQ=<br><br># The value is base64-encoded</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gPmC6sh-VUiuXYYoOHUfug.png" /><figcaption>Secret’s workflow</figcaption></figure><blockquote><a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/"><strong>PersistentVolumeClaim (PVC)</strong></a> requests storage for your application, such as logs or data storage needs, ensuring stable and persistent data availability, it simplifys storage management by abstracting the underlying storage details while ensuring data persistence for your application.</blockquote><pre>apiVersion: v1<br>kind: PersistentVolumeClaim<br>metadata:<br>  name: java-app-pvc<br>spec:<br>  accessModes:<br>    - ReadWriteOnce<br>  resources:<br>    requests:<br>      storage: 1Gi</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9bwRGwej8WBGehZbSVExog.png" /><figcaption>PVC’s workflow</figcaption></figure><h4><strong>Thank you for reading! 🙌</strong></h4><p>In this article, we explored the role of Kubernetes manifests, the common challenges developers encounter when creating them manually, and an overview of the different types of manifests.</p><p>In the upcoming “<strong>Part 2: Automating Kubernetes Manifests</strong>” we’ll delve into strategies for streamlining manifest creation and enhancing your development workflow.</p><h4>Stay tuned for more insights!🚀</h4><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ea4eea6cd61d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[[Research]: Sandboxing in GraalVM for Java Applications ]]></title>
            <link>https://medium.com/@ididyk/implementing-sandboxing-in-graalvm-for-java-applications-593ffb837238?source=rss-21d32cf45e7------2</link>
            <guid isPermaLink="false">https://medium.com/p/593ffb837238</guid>
            <dc:creator><![CDATA[Ihor Didyk]]></dc:creator>
            <pubDate>Sun, 21 Jul 2024 16:37:02 GMT</pubDate>
            <atom:updated>2024-07-23T10:52:45.087Z</atom:updated>
            <content:encoded><![CDATA[<h3>🌟<strong>Introduction</strong></h3><p>In today’s world of software development, security is paramount. One of the key strategies to enhance security is through <strong>sandboxing</strong>, which allows code to be executed in a controlled environment. <br>This article will explore <strong>how to implement secure sandboxing in GraalVM</strong>, focusing on practical examples, security policies, and best practices.</p><h3>🛡️Understanding Sandboxing and Its Importance</h3><p><strong>Sandboxing</strong> is a security mechanism used to run applications in a restricted environment. This ensures that even if an application is compromised, the damage it can cause is limited. By isolating the application from critical system resources and limiting its permissions, sandboxing provides an additional layer of security, especially in environments where code from untrusted sources may be executed.</p><p><strong>Sandboxing techniques</strong> involve creating a controlled execution environment where the application has restricted access to the host system’s resources. This is crucial for mitigating risks such as unauthorized data access, system crashes, and malicious attacks.</p><p>In the context of GraalVM, sandboxing can be effectively implemented using the <strong>Truffle API</strong> and <strong>Espresso project</strong>. GraalVM’s polyglot capabilities allow for the secure execution of code from multiple languages within the same runtime environment, providing robust security measures. <br>For an in-depth understanding of GraalVM’s approach to security, visit the <a href="https://www.graalvm.org/latest/security-guide/polyglot-sandbox/"><strong>GraalVM Security Documentation</strong></a><strong>.</strong></p><h3>🚀 Introducing GraalVM and Project Espresso</h3><p>🌐 <strong>GraalVM Overview<br>GraalVM</strong> is a high-performance runtime that provides significant advantages for running applications written in various programming languages, including <strong>Java</strong>, JavaScript, Python, Ruby, and more. It integrates with the JVM and supports <strong>ahead-of-time (AOT)</strong> <strong>compilation</strong>, offering substantial performance improvements and reduced startup times.</p><p>☕ <strong>Project Espresso Overview<br>Project Espresso</strong> is an implementation of the Java Virtual Machine (JVM) on top of the<strong> Truffle framework</strong> within GraalVM. It allows running Java bytecode with the added benefits of GraalVM’s multilingual capabilities. Espresso enables secure and efficient execution of Java applications by leveraging the <strong>Truffle framework to optimize</strong> Java bytecode execution.</p><p>It encompasses all the essential components of a Java Virtual Machine:</p><ul><li>Bytecode interpreter</li><li>Bytecode verifier</li><li>Single-pass. class file parser</li><li>Simplified object model</li><li>Java Native Interface (JNI) implemented in Java</li><li>Virtual Machine implemented in Java</li><li>Java Debug Wire Protocol (JDWP)</li></ul><p>A key aspect of this implementation is that it is entirely written in Java. This makes Java on Truffle essentially “Java on Java”! Achieving self-hosting is considered the holy grail in the research and development of Java virtual machines.</p><p>👍 <strong>Pros of Using GraalVM and Project Espresso</strong></p><ol><li><strong>Performance Improvements</strong>: GraalVM’s Just-In-Time (JIT) compiler and AOT compilation can significantly improve the performance of Java applications.</li><li><strong>Polyglot Capabilities</strong>: GraalVM allows seamless interoperability between different programming languages, enabling the integration of Java with languages like JavaScript, Python, and more.</li><li><strong>Advanced Tooling</strong>: GraalVM provides advanced tools for profiling, debugging, and monitoring applications.</li><li><strong>Security Enhancements</strong>: Project Espresso allows for sandboxing Java applications, adding an extra layer of security by running code in a restricted environment.</li><li><strong>Native Image</strong>: GraalVM’s native image feature allows Java applications to be compiled into standalone executables, improving startup times and reducing memory footprint.</li></ol><p>👎 <strong>Cons of Using GraalVM and Project Espresso</strong></p><ol><li><strong>Compatibility Issues</strong>: Some Java libraries and frameworks may not be fully compatible with GraalVM or Project Espresso.</li><li><strong>Complexity</strong>: Setting up and configuring GraalVM and Project Espresso can be more complex than using a standard JVM.</li><li><strong>Learning Curve</strong>: Developers may need to invest time in learning the new tools and features provided by GraalVM and Project Espresso.</li><li><strong>Limited Ecosystem Support</strong>: Although growing, the ecosystem around GraalVM and Project Espresso is still smaller compared to the traditional JVM ecosystem</li></ol><h3>🛠️ Setting Up Your Environment</h3><p>To get started, ensure you have GraalVM installed on your system. You can download the latest version from the <a href="https://www.graalvm.org/"><strong>GraalVM website</strong></a> or use the <a href="https://sdkman.io/"><strong>SDKman</strong></a> tool.</p><pre>sdk install java 22.3.r17-grl<br>sdk use java 22.3.r17-grl</pre><p>Once installed, configure your environment to use <strong>GraalVM</strong> as the default JVM.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Zhb9gIjO8yr76hTjRyzq8Q.png" /><figcaption>Default JDK 17 with GraalVm CE 22.3.0</figcaption></figure><p>Next, we’ll set up a Maven project with the necessary dependencies. Add the following dependencies to your pom.xml file:</p><pre>    &lt;dependencies&gt;<br>        &lt;!-- GraalVM SDK for Java --&gt;<br>        &lt;dependency&gt;<br>            &lt;groupId&gt;org.graalvm.sdk&lt;/groupId&gt;<br>            &lt;artifactId&gt;graal-sdk&lt;/artifactId&gt;<br>            &lt;version&gt;24.0.1&lt;/version&gt;<br>        &lt;/dependency&gt;<br>        &lt;!-- Truffle API --&gt;<br>        &lt;dependency&gt;<br>            &lt;groupId&gt;org.graalvm.truffle&lt;/groupId&gt;<br>            &lt;artifactId&gt;truffle-api&lt;/artifactId&gt;<br>            &lt;version&gt;24.0.1&lt;/version&gt;<br>        &lt;/dependency&gt;<br>        &lt;!-- Espresso --&gt;<br>        &lt;dependency&gt;<br>            &lt;groupId&gt;org.graalvm.espresso&lt;/groupId&gt;<br>            &lt;artifactId&gt;espresso-language&lt;/artifactId&gt;<br>            &lt;version&gt;24.0.1&lt;/version&gt;<br>            &lt;scope&gt;runtime&lt;/scope&gt;<br>        &lt;/dependency&gt;<br>    &lt;/dependencies&gt;</pre><h4>📁 Project Structure</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/978/1*AtDvEIm8DXqYTruVZKLYYQ.png" /><figcaption>GraalVM playground project structure</figcaption></figure><h3>🔒 Creating a Secure Context</h3><p>To create a secure context for running Java applications, you’ll need to configure the polyglot context in GraalVM and disable potentially risky functions such as eval.</p><p>Here’s a simple ContextManager to get you started. That provides utility methods to create and manage secured GraalVM Polyglot Context with configurations:</p><pre>import org.graalvm.polyglot.Context;<br>import org.graalvm.polyglot.HostAccess;<br><br>import static com.github.ih0rd.utils.Constants.JAVA_LANG_ID;<br><br>/**<br> * The {@code ContextManager} class provides a utility method to create a secured<br> * GraalVM polyglot {@link Context} with specific configurations.<br> * &lt;p&gt;<br> * This class is designed to prevent instantiation and only offers a static method<br> * to retrieve a configured {@link Context} instance.<br> * &lt;/p&gt;<br> */<br>public class ContextManager {<br><br>    /**<br>     * Private constructor to prevent instantiation of this utility class.<br>     */<br>    private ContextManager() {<br>    }<br><br>    /**<br>     * Creates and returns a secured GraalVM polyglot context for Java.<br>     * &lt;p&gt;<br>     * The context is configured with various security restrictions to enhance the safety<br>     * of executing untrusted code. The following restrictions are applied:<br>     * &lt;ul&gt;<br>     *   &lt;li&gt;Host access is disabled ({@code HostAccess.NONE}).&lt;/li&gt;<br>     *   &lt;li&gt;File I/O operations are not allowed ({@code allowIO(false)}).&lt;/li&gt;<br>     *   &lt;li&gt;Native access is not allowed ({@code allowNativeAccess(false)}).&lt;/li&gt;<br>     *   &lt;li&gt;Creating new processes is not allowed ({@code allowCreateProcess(false)}).&lt;/li&gt;<br>     *   &lt;li&gt;All access permissions are disabled ({@code allowAllAccess(false)}).&lt;/li&gt;<br>     *   &lt;li&gt;Experimental options are enabled ({@code allowExperimentalOptions(true)}).&lt;/li&gt;<br>     * &lt;/ul&gt;<br>     *<br>     * @return a {@link Context} instance configured with the specified security restrictions.<br>     */<br>    public static Context getSecuredContext() {<br>        return Context.newBuilder(JAVA_LANG_ID)<br>                .allowHostAccess(HostAccess.NONE)<br>                .allowIO(false)<br>                .allowNativeAccess(false)<br>                .allowCreateProcess(false)<br>                .allowAllAccess(false)<br>                .allowExperimentalOptions(true)<br>                .option(&quot;engine.WarnInterpreterOnly&quot;,&quot;false&quot;)<br>                .build();<br>    }<br><br>}</pre><p>Also, we need GraalVMExecutor to manage the execution of operations within a secured GraalVM Polyglot context:</p><pre>import com.github.ih0rd.exceptions.GraalVMPlaygroundException;<br>import com.oracle.truffle.api.*;<br><br><br>import org.graalvm.polyglot.Context;<br><br>/**<br> * A class to manage the execution of operations within a secured GraalVM polyglot context.<br> */<br>public class GraalVmExecutor implements AutoCloseable{<br><br>    private final Context context;<br><br>    /**<br>     * Constructs a new GraalVmExecutor with a secured GraalVM polyglot context.<br>     */<br>    public GraalVmExecutor() {<br>        context = ContextManager.getSecuredContext();<br>    }<br><br>    /**<br>     * Loads a class into the GraalVM polyglot context, creates an instance of the class,<br>     * and retrieves it from the context&#39;s polyglot bindings.<br>     *<br>     * @param &lt;T&gt;   The type of the class to be loaded.<br>     * @param clazz The class to be loaded and instantiated.<br>     * @return An instance of the class loaded from the context&#39;s polyglot bindings.<br>     * @throws GraalVMPlaygroundException if the class cannot be loaded or instantiated.<br>     */<br>    public &lt;T&gt; T loadClassIntoContext(Class&lt;T&gt; clazz) {<br>        try {<br>            var instance = clazz.getDeclaredConstructor().newInstance();<br>            var memberName = clazz.getSimpleName();<br>            context.getPolyglotBindings().putMember(memberName, instance);<br>            return context.getPolyglotBindings().getMember(memberName).as(clazz);<br>        } catch (Exception e) {<br>            throw new GraalVMPlaygroundException(&quot;Failed to load class into context&quot;, e);<br>        }<br>    }<br><br>    /**<br>     * Executes a specified method of a given class with provided arguments using Truffle.<br>     *<br>     * @param clazz      The class containing the method to be executed.<br>     * @param methodName The name of the method to be executed.<br>     * @param args       The arguments to be passed to the method during execution.<br>     * @return The result of the method execution.<br>     */<br>    public Object executeMethod(Class&lt;?&gt; clazz, String methodName, Object... args) {<br>        var runtime = Truffle.getRuntime();<br>        var javaNode = new JavaNode(clazz, methodName, args);<br>        var directCallNode = runtime.createDirectCallNode(javaNode.getCallTarget());<br>        return directCallNode.call(args);<br>    }<br><br><br>    /**<br>     * Closes the GraalVM polyglot context if it is open.<br>     */<br>    public void closeContext() {<br>        if (context != null) {<br>            context.close();<br>        }<br>    }<br><br>    @Override<br>    public void close() throws Exception {<br>        closeContext();<br>    }<br>}</pre><p>The GraalVmExecutor class is designed to manage the execution of operations within a secured GraalVM polyglot context. It demonstrates how to securely load and execute Java classes and methods using the Truffle API, ensuring that an execution is contained within a sandboxed environment. This approach enhances security by preventing unauthorized access and potential vulnerabilities.</p><p>For now, we are ready to load some Java implementation from GraalVM. Here’s a correct example to get you started:</p><pre>public class HelloWorld {<br>    public void printHello() {<br>        System.out.println(&quot;Hello, secure GraalVM context with Espresso!&quot;);<br>    }<br><br>    public int simplyMultiply(int a, int b) {<br>        return a * b;<br>    }<br>}</pre><p>To demonstrate the practical usage of the GraalVmExecutor class, we can create a simple application that initializes the executor, loads a class, and executes methods within the secured GraalVM context. The following GraalvmPlaygroundApplication class serves as an entry point, showcasing how to perform these operations seamlessly.</p><pre>import com.github.ih0rd.domain.HelloWorld;<br>import com.github.ih0rd.helpers.GraalVmExecutor;<br><br>public class GraalvmPlaygroundApplication {<br><br>    public static void main(String[] args) {<br><br>        var graalVMExecutor = new GraalVmExecutor();<br><br>        HelloWorld helloWorld = graalVMExecutor.loadClassIntoContext(HelloWorld.class);<br>        helloWorld.printHello();<br>        System.out.println(&quot;helloWorld.simplyMultiply(2,5) = &quot; + helloWorld.simplyMultiply(2, 5));<br><br>        // Execute method via Truffle API &amp; Espresso<br>        Object printHelloResult = graalVMExecutor.executeMethod(HelloWorld.class, &quot;printHello&quot;);<br>        System.out.println(&quot;printHelloResult = &quot; + printHelloResult);<br>        <br>        Object simplyMultiplyResult = graalVMExecutor.executeMethod(HelloWorld.class, &quot;simplyMultiply&quot;, 2, 3);<br>        System.out.println(&quot;simplyMultiplyResult = &quot; + simplyMultiplyResult);<br>        <br>        graalVMExecutor.closeContext();<br>    }<br><br>}</pre><h3>⚙️ Configuring &#39;--add-exports&#39; for GraalVM</h3><blockquote>The --add-exports options are necessary because they allow the GraalVM runtime to access specific internal APIs required by the Truffle framework and the Espresso project. <br>These configurations ensure that your application can utilize these APIs without running into access restrictions that could prevent it from functioning correctly. Properly configuring these options is important to avoid errors such as <em>NoClassDefFoundError</em> or <em>ClassNotFoundException</em>.<br>Proper configuration also enhances security by explicitly specifying which internal packages are accessible, thus preventing unintended exposure other system .</blockquote><h4>🛠️ Maven Configuration</h4><p>Add the necessary plugins and configurations to your pom.xml to include the --add-exports options when building your project:</p><pre>    &lt;properties&gt;<br>        &lt;java.version&gt;17&lt;/java.version&gt;<br>        &lt;graal.version&gt;24.0.1&lt;/graal.version&gt;<br>        &lt;plugin.encoding&gt;UTF-8&lt;/plugin.encoding&gt;<br>        &lt;manifest.mainClass&gt;com.github.ih0rd.GraalvmPlaygroundApplication&lt;/manifest.mainClass&gt;<br>    &lt;/properties&gt;<br>    <br>    &lt;build&gt;<br>        &lt;plugins&gt;<br>            &lt;plugin&gt;<br>                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;<br>                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;<br>                &lt;version&gt;3.13.0&lt;/version&gt;<br>                &lt;configuration&gt;<br>                    &lt;source&gt;${java.version}&lt;/source&gt;<br>                    &lt;target&gt;${java.version}&lt;/target&gt;<br>                    &lt;release&gt;${java.version}&lt;/release&gt;<br>                    &lt;encoding&gt;${plugin.encoding}&lt;/encoding&gt;<br>                &lt;/configuration&gt;<br>            &lt;/plugin&gt;<br>            &lt;plugin&gt;<br>                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;<br>                &lt;artifactId&gt;maven-jar-plugin&lt;/artifactId&gt;<br>                &lt;version&gt;3.4.2&lt;/version&gt;<br>                &lt;configuration&gt;<br>                    &lt;archive&gt;<br>                        &lt;manifestEntries&gt;<br>                            &lt;Add-Exports&gt;<br>                                org.graalvm.truffle/com.oracle.truffle.api=ALL-UNNAMED,<br>                                org.graalvm.truffle/com.oracle.truffle.api.frame=ALL-UNNAMED,<br>                                org.graalvm.truffle/com.oracle.truffle.api.nodes=ALL-UNNAMED,<br>                                org.graalvm.truffle/com.oracle.truffle.api.source=ALL-UNNAMED<br>                            &lt;/Add-Exports&gt;<br>                        &lt;/manifestEntries&gt;<br>                        &lt;manifest&gt;<br>                            &lt;mainClass&gt;${manifest.mainClass}&lt;/mainClass&gt;<br>                        &lt;/manifest&gt;<br>                    &lt;/archive&gt;<br>                &lt;/configuration&gt;<br>            &lt;/plugin&gt;<br>            &lt;plugin&gt;<br>                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;<br>                &lt;artifactId&gt;maven-shade-plugin&lt;/artifactId&gt;<br>                &lt;version&gt;3.5.3&lt;/version&gt;<br>                &lt;executions&gt;<br>                    &lt;execution&gt;<br>                        &lt;phase&gt;package&lt;/phase&gt;<br>                        &lt;goals&gt;<br>                            &lt;goal&gt;shade&lt;/goal&gt;<br>                        &lt;/goals&gt;<br>                        &lt;configuration&gt;<br>                            &lt;transformers&gt;<br>                                &lt;transformer<br>                                        implementation=&quot;org.apache.maven.plugins.shade.resource.ManifestResourceTransformer&quot;&gt;<br>                                    &lt;mainClass&gt;${manifest.mainClass}&lt;/mainClass&gt;<br>                                &lt;/transformer&gt;<br>                            &lt;/transformers&gt;<br>                            &lt;filters&gt;<br>                                &lt;filter&gt;<br>                                    &lt;artifact&gt;*:*&lt;/artifact&gt;<br>                                    &lt;excludes&gt;<br>                                        &lt;exclude&gt;module-info.class&lt;/exclude&gt;<br>                                        &lt;exclude&gt;META-INF/MANIFEST.MF&lt;/exclude&gt;<br>                                        &lt;exclude&gt;<br>                                            META-INF/services/com.oracle.truffle.api.instrumentation.provider.TruffleInstrumentProvider<br>                                        &lt;/exclude&gt;<br>                                        &lt;exclude&gt;<br>                                            META-INF/services/com.oracle.truffle.api.provider.TruffleLanguageProvider<br>                                        &lt;/exclude&gt;<br>                                    &lt;/excludes&gt;<br>                                &lt;/filter&gt;<br>                            &lt;/filters&gt;<br>                            &lt;createDependencyReducedPom&gt;false&lt;/createDependencyReducedPom&gt;<br>                        &lt;/configuration&gt;<br>                    &lt;/execution&gt;<br>                &lt;/executions&gt;<br>            &lt;/plugin&gt;<br>            &lt;plugin&gt;<br>                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;<br>                &lt;artifactId&gt;maven-resources-plugin&lt;/artifactId&gt;<br>                &lt;version&gt;3.3.1&lt;/version&gt;<br>                &lt;configuration&gt;<br>                    &lt;encoding&gt;${plugin.encoding}&lt;/encoding&gt;<br>                &lt;/configuration&gt;<br>            &lt;/plugin&gt;<br>        &lt;/plugins&gt;<br>    &lt;/build&gt;</pre><h4>🖥️ IntelliJ IDEA Configuration</h4><p>To run your project from IntelliJ IDEA with the necessary --add-exports options, follow these steps:</p><ul><li><strong>Open IntelliJ IDEA</strong>:<br>- Open your project in IntelliJ IDEA.</li><li><strong>Edit Run/Debug Configuration</strong>:<br>- Go to Run -&gt; Edit Configurations...</li><li><strong>Select your Application Configuration</strong>:<br>- select the configuration for your main class, or create a new one if it doesn’t exist.</li><li><strong>Add VM Options</strong>:<br>- In the VM options field, add the following options to grant access to the necessary packages:</li></ul><pre>--add-exports=org.graalvm.truffle/com.oracle.truffle.api=ALL-UNNAMED<br>--add-exports=org.graalvm.truffle/com.oracle.truffle.api.frame=ALL-UNNAMED<br>--add-exports=org.graalvm.truffle/com.oracle.truffle.api.nodes=ALL-UNNAMED<br>--add-exports=org.graalvm.truffle/com.oracle.truffle.api.source=ALL-UNNAMED<br>--add-exports=org.graalvm.truffle/com.oracle.truffle.api.exception=ALL-UNNAMED<br>--add-exports=org.graalvm.truffle/com.oracle.truffle.api.staticobject=ALL-UNNAMED</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZbICy33wqEiDkVa9vaS1zw.png" /><figcaption>Run/Debug configurations of IDE project</figcaption></figure><h4>🚀 Building and Running with java -jar</h4><p>To build and run your project using java -jar, follow these steps:</p><ul><li><strong>Build the Project</strong>:<br>Run the Maven build command to create the shaded JAR:</li></ul><pre>mvn clean package</pre><ul><li><strong>Run the Shaded JAR</strong>:<br>Use the java -jar command to run your JAR file:</li></ul><pre>java -jar target/graalvm-playground-0.0.1-SNAPSHOT.jar</pre><h3>🎉 Conclusion</h3><p>Implementing sandboxing in GraalVM using the Truffle API and Espresso project offers a robust way to securely execute Java applications. By leveraging GraalVM’s capabilities, developers can create controlled environments that limit the access of executed code to the host system, thereby mitigating potential security risks.</p><p>In this article, we explored:</p><ul><li><strong>Techniques for Secure Sandboxing in GraalVM</strong>: <br>Understanding how sandboxing works and how GraalVM, Truffle, and Espresso can be used to create a secure environment.</li><li><strong>Practical Examples and Best Practices</strong>: <br>Detailed examples demonstrating how to set up GraalVM, configure a secure context and execute methods within the sandbox using the Truffle API.</li></ul><p>By following these techniques and best practices, you can enhance the security of your Java applications. GraalVM’s sandboxing capabilities, combined with Truffle and Espresso, provide a powerful toolset for running Java code in a secure and controlled manner. This approach helps in preventing unauthorized access and potential security vulnerabilities, ensuring your applications run safely and securely.</p><p>Feel free to reach out with any questions or share your experiences in the comments below. Your feedback is invaluable as we explore the capabilities of GraalVM together. Happy coding!</p><p>Check out the complete code and examples on my <a href="https://github.com/ih0r-d/graalvm-playground">GitHub repository.</a></p><p>#GraalVM #Java #Security #Sandboxing #ProjectEspresso #TruffleFramework #Polyglot #Programming #DevOps</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=593ffb837238" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[[Experimental]: GraalVM as a Platform for Python and Java Polyglot Programming ]]></title>
            <link>https://medium.com/@ididyk/experimental-graalvm-as-a-platform-for-python-and-java-polyglot-programming-365f8848dddd?source=rss-21d32cf45e7------2</link>
            <guid isPermaLink="false">https://medium.com/p/365f8848dddd</guid>
            <category><![CDATA[graalvm]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[graalpython]]></category>
            <dc:creator><![CDATA[Ihor Didyk]]></dc:creator>
            <pubDate>Thu, 27 Jun 2024 20:15:11 GMT</pubDate>
            <atom:updated>2024-07-01T08:58:51.443Z</atom:updated>
            <content:encoded><![CDATA[<h3>🚀 Introduction</h3><p>As a software developer constantly striving to optimize processes, I recently faced a significant challenge: <strong><em>maintaining separate Python services for individual functions in our Java microservice architecture</em></strong>. <br>It was a hassle, causing unnecessary delays in deployment and adding complexity.</p><p>In this article, I’ll talk about <a href="https://www.graalvm.org/latest/reference-manual/python/"><strong>GraalPy</strong></a>, which can be used as a platform to execute <strong>Python</strong> code directly into our Java microservices using the <a href="https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/package-summary.html"><strong>GraalVM Polyglot API</strong></a>, transforming our workflow and saving valuable time.</p><h3>🔍 The Problem</h3><p>In our microservices architecture, we relied on Python to perform specific tasks, such as data processing, analytics, or simplex algorithms. At first, we deployed them as separate services.</p><p>However, this approach soon revealed its drawbacks. Each minor update required a full deployment cycle, which increased the workload of our DevOps team and led to delays. In addition, maintaining these isolated services created complexity and multiple points of failure in our system.</p><h3>💡Discovering Graalpy</h3><p>During one of my research sessions, I came across <a href="https://www.graalvm.org/latest/reference-manual/python/"><strong>GraalPy</strong></a>, a project under GraalVM that promised seamless integration of Python code into Java applications.</p><p>Although the project is still experimental, embedding Python functions directly into our Java microservices is intriguing. I am hopeful but cautious, as integrating two different programming languages can cause unforeseen problems.</p><h3>🛠️ The Investigation Journey</h3><p>Before we begin our research, a few details about the GraalPy, namely Python runtime from the <a href="https://www.graalvm.org/latest/reference-manual/python/Python-Runtime/">documentation</a>.</p><blockquote>GraalPy provides a Python 3.10-compliant runtime. A primary goal is to support PyTorch, SciPy, and their constituent libraries, as well as to work with other data science and machine learning libraries from the rich Python ecosystem. GraalPy is distributed as an ahead-of-time compiled native executable, compact.</blockquote><p>Let’s get back to the task, that was simple — to implement a <strong><em>universal approach to executing Python code with a minimum number of external libraries.</em></strong></p><h4>🔧 Now, let’s delve into the implementation details.</h4><h4>* Project setup</h4><p>To begin with, I created a maven project using the following command and the next versions of the tools: <strong><br></strong>✔<strong> </strong>Maven 3.8.4<br>✔ Java 21.0.3-graal</p><pre>mvn archetype:generate \<br>  -DarchetypeGroupId=org.graalvm.python \<br>  -DarchetypeArtifactId=graalpy-archetype-polyglot-app \<br>  -DarchetypeVersion=24.0.0</pre><h4>* Dependencies</h4><p>To integrate Python code into our Java microservices, we utilized the following dependencies, ensuring seamless interaction between Java and Python through Graalpy:</p><pre>&lt;dependencies&gt;<br>        &lt;!--<br>            This dependency includes the necessary polyglot functionalities provided by GraalVM,<br>            allowing multiple languages to interoperate within the same JVM.<br>        --&gt;<br>        &lt;dependency&gt;<br>            &lt;groupId&gt;org.graalvm.polyglot&lt;/groupId&gt;<br>            &lt;artifactId&gt;${graalpy.edition}&lt;/artifactId&gt;<br>            &lt;version&gt;${graalpy.version}&lt;/version&gt;<br>            &lt;type&gt;pom&lt;/type&gt;<br>        &lt;/dependency&gt;<br><br>       &lt;!--<br>            The polyglot library facilitates the execution of code from different programming languages<br>            in a single application. It provides the core API for embedding and running Python scripts<br>            within the Java environment.<br>        --&gt;<br>        &lt;dependency&gt;<br>            &lt;groupId&gt;org.graalvm.polyglot&lt;/groupId&gt;<br>            &lt;artifactId&gt;polyglot&lt;/artifactId&gt;<br>            &lt;version&gt;${graalpy.version}&lt;/version&gt;<br>        &lt;/dependency&gt;<br>        &lt;!--<br>            he python-launcher dependency includes the components needed to launch and manage Python scripts<br>            from a Java application. It handles the initialization and execution of Python code<br>            within the GraalVM environment.<br>        --&gt;<br>        &lt;dependency&gt;<br>            &lt;groupId&gt;org.graalvm.python&lt;/groupId&gt;<br>            &lt;artifactId&gt;python-launcher&lt;/artifactId&gt;<br>            &lt;version&gt;${graalpy.version}&lt;/version&gt;<br>        &lt;/dependency&gt;<br>        &lt;!--<br>            This library provides the necessary tools for embedding Python code directly into Java applications. <br>            It ensures that the Python runtime is properly integrated and managed alongside the Java runtime.<br>        --&gt;<br>        &lt;dependency&gt;<br>            &lt;groupId&gt;org.graalvm.python&lt;/groupId&gt;<br>            &lt;artifactId&gt;python-embedding&lt;/artifactId&gt;<br>            &lt;version&gt;${graalpy.version}&lt;/version&gt;<br>        &lt;/dependency&gt;<br>    &lt;/dependencies&gt;</pre><p>These dependencies collectively enable a seamless and efficient integration of Python functions into our Java microservices, leveraging the power of GraalVM for cross-language execution.</p><h3>* Configuring the Graalpy Maven Plugin</h3><p>To facilitate the integration of Python code in our Java microservices, we used the Graalpy Maven Plugin. This plugin simplifies the process of embedding Python packages and managing the Python runtime within a Java application. Below is the configuration we used:</p><pre>&lt;plugin&gt;<br>    &lt;groupId&gt;org.graalvm.python&lt;/groupId&gt;<br>    &lt;artifactId&gt;graalpy-maven-plugin&lt;/artifactId&gt;<br>    &lt;version&gt;${graalpy.version}&lt;/version&gt;<br>    &lt;executions&gt;<br>        &lt;execution&gt;<br>            &lt;configuration&gt;<br>                &lt;packages&gt;<br>                    &lt;package&gt;termcolor&lt;/package&gt;<br>                &lt;/packages&gt;<br>                &lt;pythonHome&gt;<br>                    &lt;includes&gt;<br>                        &lt;include&gt;.*&lt;/include&gt;<br>                    &lt;/includes&gt;<br>                    &lt;excludes&gt;&lt;/excludes&gt;<br>                &lt;/pythonHome&gt;<br>            &lt;/configuration&gt;<br>            &lt;goals&gt;<br>                &lt;goal&gt;process-graalpy-resources&lt;/goal&gt;<br>            &lt;/goals&gt;<br>        &lt;/execution&gt;<br>    &lt;/executions&gt;<br>&lt;/plugin&gt;</pre><h4>Key Configuration Elements</h4><ul><li><strong>Execution Configuration</strong>: This section configures how the plugin processes <strong>GraalPy</strong> resources:</li><li><strong>Packages</strong>: Specifies the Python packages to include. In this example, we include the termcolor package.</li><li><strong>Python Home Configuration</strong>: Defines the files and directories to include or exclude from the Python home. Here, all files are included (&lt;include&gt;.*&lt;/include&gt;).</li><li><strong>Goals</strong>: Specifies the goal to execute, which in this case is process-graalpy-resources.</li></ul><p>Using this configuration, the <strong>Graalpy Maven Plugin</strong> ensures that the necessary Python packages and runtime configurations are properly processed and embedded within the Java application, streamlining the integration process and reducing the complexity of managing separate Python service</p><p>Please be aware that most native extension packages do not provide precompiled binaries for GraalPy. Consequently, these packages will attempt to compile themselves on the user’s computer during installation. <br>Ensure that you have all necessary libraries and development tools installed beforehand.</p><p>The GraalVM team recommends using the <a href="https://www.graalvm.org/python/compatibility/"><strong>Python Compatibility Checker</strong></a> as the first step to determine if a package is compatible with GraalPy.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*YVxaEQ2B1vkgT9o24pFDBQ@2x.jpeg" /></figure><h3>* Implementing a Universal Approach with Reflection and Generics ⚙️</h3><p>After setting up the project, let’s dive into the Java implementation. I’ve used reflection and generalization to create a universal approach for integrating Python functions. Here is a detailed guide on how to achieve this:</p><p>In our Java implementation, I defined several constants to manage paths and configurations efficiently. Here’s a breakdown of these constants and their usage:</p><pre>//    This constant holds the string &quot;python&quot;, representing the Python programming language.<br>//    It&#39;s used to specify the language context within the GraalVM.<br>    String PYTHON = &quot;python&quot;;<br><br>//    This constant defines the prefix for the virtual environment (venv) directory.<br>//    It&#39;s used to specify the path where the Python virtual environment is located.<br>    String VENV_PREFIX = &quot;/vfs/venv&quot;;<br><br>//    This constant sets the prefix for the home directory within the virtual file system (vfs).<br>//    It helps in organizing user-specific data.<br>    String HOME_PREFIX = &quot;/vfs/home&quot;;<br><br>//    This constant defines the prefix for the project directory within the virtual file system.<br>//    It is used to structure project-specific files and resources.<br>    String PROJ_PREFIX = &quot;/vfs/proj&quot;;<br><br>//    This constant retrieves the current user directory where the Java application is running.<br>//    It is dynamically set using System.getProperty(&quot;user.dir&quot;).<br>    String USER_DIR = System.getProperty(&quot;user.dir&quot;);<br><br>//    This constant retrieves the current user directory where the Java application is running.<br>//    It is dynamically set using System.getProperty(&quot;user.dir&quot;).<br>    String RESOURCES_PREFIX = USER_DIR + &quot;/src/main/resources&quot;;<br><br>//    This constant creates the full path to the project resources directory by <br>//    concatenating RESOURCES_PREFIX with PROJ_PREFIX.<br>    String PROJ_RESOURCES_PATH = RESOURCES_PREFIX + PROJ_PREFIX;</pre><p>Python code located in the resources folder:</p><pre>src/main/resources/<br>└── vfs<br>    └── proj</pre><p>After building the project with Maven, the GraalPy plugin installs the specified packages and sets up the necessary directories, including home, venv, and other required subfolders/files.</p><pre>target/classes/vfs<br>├── home<br>│   ├── lib-graalpython<br>│   │   ├── modules<br>│   │   └── patches<br>│   └── lib-python<br>│       └── 3<br>├── proj<br>└── venv<br>    ├── bin<br>    ├── include<br>    └── lib<br>        └── python3.10<br><br>The overall structure of the project is as follows:<br>12 directories</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0APbDFaX7wSZAThvl8qBXg.png" /></figure><p>Let’s delve into the core implementation magic with an example of using Python code for a simplex algorithm 🧐.</p><p>The <strong>simplex method</strong> is a technique for solving linear programming models manually. It involves using slack vars, tables, and pivot variables to find the optimal solution to an optimization problem. Linear programming aims to achieve the best result (maximum or minimum) within given linear constraints. For more details, you can read these.</p><p><a href="https://en.wikipedia.org/wiki/Simplex_algorithm">Simplex algorithm - Wikipedia</a></p><p><strong>GraalVM</strong> exported the <strong>Python class to Java </strong>as our explicit interface with the Java side. <br>What does this mean in practice?</p><ul><li>optimize_service.py contains the class implementing the simplex method.</li><li>OptimizeService.java defines the interface on the Java side, serving as a contract with the Python implementation.</li></ul><blockquote><strong><em>[NOTES] <br></em></strong><em>You need to carefully export the implication through the polyglot package (line 476 in the image)</em></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_0__gU8r-A3c8LwhBAA82A.png" /><figcaption><strong>Python Class vs Java Interface</strong>: Serving as a contract between implementation and abstraction.</figcaption></figure><h3>What Did I Implement?</h3><p>To realize this approach, I used the Reflection API along with a configured polyglot context and generics to achieve the following steps:</p><ol><li><strong>Configure Polyglot Context</strong>: Set up the GraalVM polyglot context to allow interoperability between Java and Python.</li><li><strong>Retrieve Methods from Interface</strong>: Obtain a list of methods from the Java interface using reflection.</li><li><strong>Verify Method Presence in Python Class</strong>: Check if the corresponding methods exist in the Python class.</li><li><strong>Invoke Methods Dynamically</strong>: Utilize reflection to dynamically invoke these methods, ensuring a seamless integration between the Java interface and the Python implementation.</li><li><strong>Leverage Generics</strong>: Implement generics to handle different input and output types, enhancing flexibility and type safety.</li></ol><p>This implementation leverages the power of reflection, a configured polyglot context, and generics to bridge the gap between the Java interface and the Python class. It enables flexible and dynamic method invocation while ensuring type safety and seamless integration.</p><h4>* Example usage simplex method from Python implementation:</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*H9eExHJTpauEaVxdsnRzPw.png" /><figcaption><strong>src/main/java/com/github/ih0rd/GraalPyRunner.java</strong></figcaption></figure><h3>* PythonExecutor</h3><p>The PythonExecutor a class implements the evaluation logic for both parameterized and non-parameterized methods. This class can handle methods that return values as well as void methods using reflection&#39;s invokeMethod. Here&#39;s a technical breakdown:</p><ul><li><strong>Method Invocation</strong>: It supports both methods with and without parameters.</li><li><strong>Handling Return Types</strong>: The methods in PythonExecutor can manage both void and non-void methods. For methods that return values, the result is processed and returned.</li><li><strong>Return Values Management</strong>: The methods return a Map containing the returnedType and result. For void methods, the result is represented as Optional.empty().</li><li>Method mapValue return maps a polyglot value to a value with a given Java target type.</li></ul><p>This approach ensures flexibility and type safety, allowing for dynamic method invocation and handling various method signatures seamlessly.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KiELKdk8wHOh-Y0IqPB2tg.png" /><figcaption><strong>src/main/java/com/github/ih0rd/helpers/PythonExecutor.java</strong></figcaption></figure><h3>* PolyglotHelper</h3><p>The PolyglotHelper the utility class to configure context, source and options for VirtualFileSystem and managing embedded resources such as project and home files.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*D3ycUzyBNN4BOq6fE4VrEQ.png" /><figcaption><strong>src/main/java/com/github/ih0rd/helpers/PolyglotHelper.java</strong></figcaption></figure><h3>* Real-world Impact</h3><p>The benefits were immediate and significant. Deployment times were reduced since we no longer needed to deploy separate Python services. Our architecture became cleaner, with fewer moving parts and less maintenance overhead. Overall, the integration streamlined our workflow, allowing us to focus more on development and less on operational issues.</p><h3>Lessons Learned</h3><p>This experience taught me several valuable lessons:</p><ol><li><strong>Integration Simplicity</strong>: Tools like Graalpy can significantly simplify cross-language integration.</li><li><strong>Performance Considerations</strong>: While the integration was smooth, monitoring performance is crucial to ensure it meets your application needs.</li><li><strong>Documentation and Community Support</strong>: Leveraging well-documented tools with active community support can mitigate many integration challenges.</li><li><strong>Ease of extension</strong>: If you need new functionality, add a Python implementation and a corresponding Java interface, and you can easily use it through the PythonExecutor</li></ol><h3>Conclusion</h3><p>Integrating Python code into our Java microservices using GraalPy was a game-changer. It not only streamlined our deployment process but also reduced the complexity of our architecture. If you have faced similar challenges, I recommend you explore this approach. It could save you time and effort, just as it did for us.<br>If you are interested in my realization, you can see it on <a href="https://github.com/ih0r-d/graalpy-polyglot-playground"><strong>GitHub</strong></a></p><h3>Call to Action</h3><p>Have you tried integrating different programming languages into your projects? Share your experiences and the best tips you have in the comments below! <br>If you enjoyed this article, follow me for more insights on software development and microservices.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=365f8848dddd" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>