{"id":15019328,"url":"https://github.com/piran-framework/ganjex","last_synced_at":"2025-05-02T07:33:20.686Z","repository":{"id":47678832,"uuid":"125724224","full_name":"piran-framework/ganjex","owner":"piran-framework","description":"Passive Container With Runtime Lifecycle Management","archived":false,"fork":false,"pushed_at":"2023-12-05T22:19:17.000Z","size":278,"stargazers_count":12,"open_issues_count":3,"forks_count":4,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-10-29T22:56:39.678Z","etag":null,"topics":["classloader","container","pure-java","runtime","spring-boot"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/piran-framework.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-03-18T12:47:51.000Z","updated_at":"2021-08-18T12:02:30.000Z","dependencies_parsed_at":"2024-10-10T05:31:18.696Z","dependency_job_id":"7de25662-4cc7-4492-ab73-3742400f87c9","html_url":"https://github.com/piran-framework/ganjex","commit_stats":{"total_commits":84,"total_committers":6,"mean_commits":14.0,"dds":0.25,"last_synced_commit":"b0a12ab04423aa4f0b0c0ccd1851ad6a2e5d0a45"},"previous_names":["behsa-oss/ganjex"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piran-framework%2Fganjex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piran-framework%2Fganjex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piran-framework%2Fganjex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piran-framework%2Fganjex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/piran-framework","download_url":"https://codeload.github.com/piran-framework/ganjex/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224305839,"owners_count":17289446,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["classloader","container","pure-java","runtime","spring-boot"],"created_at":"2024-09-24T19:53:20.643Z","updated_at":"2024-11-12T16:04:55.495Z","avatar_url":"https://github.com/piran-framework.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Ganjex\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.piran-framework/ganjex/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.piran-framework/ganjex)\n[![Travis IC](https://travis-ci.org/piran-framework/ganjex.svg?branch=master)](https://travis-ci.org/piran-framework/ganjex)\n[![Codacy Badge](https://api.codacy.com/project/badge/Grade/5bb12607be964e478f507fd04de0fc21)](https://www.codacy.com/app/esahekmat/ganjex?utm_source=github.com\u0026amp;utm_medium=referral\u0026amp;utm_content=piran-framework/ganjex\u0026amp;utm_campaign=Badge_Grade)\n[![Javadocs](http://javadoc.io/badge/com.piran-framework/ganjex.svg)](http://javadoc.io/doc/com.piran-framework/ganjex)\n\nThere are  situations when you want to serve lots of dynamic services by just one JVM(runtime), with the \nhelp of Ganjex you can define your own framework.When you are developing micro-services, usually \nevery micro service need a dedicated JVM, and any changes in it need restarting JVM. Remember \ntomcat which contains webapps and you can change webapps by removing or changing WAR files \nwithout restarting tomcat itself, but tomcat forces you to define your application in webapp \nschema, tomcat searches for servlet you defined and route HTTP messages to them. So if you want \nyour micro-services communicating with each other by a queue for example or using gRPC you can't \nuse tomcat simply to serve your micro-services. Also if you want to develop your services in a \ndifferent manner than webapp and servlet, you can't use tomcat. OSGi is another solution but its \ntoo complicated and has a high learning curve. Ganjex like tomcat can contain services, and each \nservice has its own classloader and lifecycle, but unlike tomcat which searches for servlets in \nits containing webapps, Ganjex is oblivious to its holding services, so we say Ganjex is a \npassive container just facilitating the management of the containing elements' alterations and \nlifecycle at runtime. The way this container should behave with its services (remember tomcat \nwhich searches for servlet and routes HTTP messages to them) should be defined by the client \nwhich uses Ganjex. So we say Ganjex is a platform layer container, which user must define their \nown framework based on their necessities and preferences properly. There are two types of \nelements Ganjex contains 1. Library and 2. Service.      \n\n## Framework\nIt is expected that application framework, also called as client, would define how it plans to \ntreat containing services. Ganjex container is started by framework with the code below:\n ```\n Ganjex.run(ganjexConfiguration);\n ```\n In the above code `ganjexConfiguration` is a configuration instance of `GanjexConfiguration` \n class which should be created by `GanjexConfiguration.Builder`. As an illustration:\n ```\n \tGanjex ganjex = //you can save an instance of Ganjex container in Ganjex object\n \t    Ganjex.run(new GanjexConfiguration.Builder()\n \t        .libPath(\"/opt/ganjex/lib\")         //location where libraries should be added\n \t        .servicePath(\"/opt/ganjex/service)  //location where services should be added\n \t        .watcherDelay(4)                    //how many seconds watchers should wait to retry\n \t        .hooks(new SomeHookContainer())     //list of all objects containing hooks\n \t        .build());\n ``` \nPlease note that `SomeHookContainer` class in the above example may have methods annotated with \n`@StartupHook` or `@ShutdownHook` in order to manage the lifecycle of services. This is an \nexample of this class:\n```\npublic class SomeHookContainer {\n    @StartupHook\n    public void start(ServiceContext context){\n        //consequent behavior changes mandated by the newly added service\n    }\n    \n    @ShutdownHook\n    public void destroy(ServiceContext context){\n        //consequent fallback changes mandated by the newly added service\n    }\n} \n```\nThe service classLoader is required to surf the service code to manage business necessities \ndefined by framework, so the service classLoader would be provided by the ServiceContext object.\nIn other words, Ganjex would behave in a way that is defined in the framework by the client. \n\n## Service     \nAccomplishing specific jobs, services are interchangeable units typically implement a use case. \nAs business use cases are being frequently changed, Ganjex services are supposed to be changed\nrepetitively as well. As soon as a requirement is changed, the implementation of that requirement must \nbe changed and deployed consequently. In Ganjex, also, services could be deployed or removed at runtime \n(on the fly). Soon after a service is added to Ganjex container, all of the `@StartupHook` methods  \nwould be notified with the `ServiceContext` of the newly added service. Similarly, right after a \nservice is removed from Ganjex container, all of the frameworks' methods annotated with \n`@ShutdownHook` would be notified with the `ServiceContext` of that service. \nThis is framework's responsibility to treat each service properly, due to the fact that Ganjex \nknows nothing of the structure and pattern services utilize. Remember frameworks are not \nexpected to be changed frequently.\n\n### Service manifest\nEvery service should have a file named *manifest.properties* in the root of its classpath. This \nis a manifest clearing the service identity. This should contain two keys: *name* and *version*\n\n## Library\nThere are cases when multiple services need a class, or a domain model class should be shared \nbetween services. As we can have many services, this might bring about having duplicate shared code \nin the services which would be inefficient and difficult to maintain. Here Libraries come to \nrescue, Libraries are typical jar files which can be changed and required to be accessible to the\nservices. A service needing a library, should \nadd the library's corresponding Maven dependency with `\u003cscope\u003eprovided\u003c/scope\u003e` because it would \nbe provided by Ganjex at runtime.\n\nPlease note that changing the libraries is costly, meaning that soon after a library is changed \n(modified, added or removed), all of the services would be restarted in order to affect the \nconsequent changes.\n\n## Dependency\nTo use ganjex library in your project add this dependency into your project pom:\n```\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.piran-framework\u003c/groupId\u003e\n    \u003cartifactId\u003eganjex\u003c/artifactId\u003e\n    \u003cscope\u003e0.4-RELEASE\u003c/scope\u003e\n\u003c/dependency\u003e\n```\n\n## Use Spring-Boot and Ganjex simultaneously\nA Spring-boot-starter has been particularly designed for Ganjex which could be mounted on \nSpring-boot applications. By adding `@EnableGanjexContainer` class-level annotation on the \nConfiguration class, Ganjex starts and scans all the beans with `@GanjexHook` annotation. Note \nthat, if a class is marked with `@GanjexHook`, that class would be qualified to be a Spring \ncomponent bean as well, so there would be no need to add @Component or @Service by doing so.\n\n### Spring-Boot properties \nTo add ganjex-starter to a spring-boot application, add three properties besides spring-boot \nproperties:\n* ganjex.lib-path\n* ganjex.service-path\n* ganjex.watch-delay\n\nThey are the same as `GanjexConfiguration` fields.\n\n## Sample Guide\nThere is a sample dynamic web framework developed using Spring and Ganjex, Full guide also available in \n[its directory](sample/sampleWebFramework)\n\n## Minimum Requirement\nYou need at least java 8 to use Ganjex container.\n\n## License\nCopyright (c) 2018 Isa Hekmatizadeh.\n\nGanjex is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser \nGeneral Public License as published by the Free Software Foundation, either version 3 of the \nLicense, or (at your option) any later version.\n\nGanjex is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the\nimplied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU Lesser General \nPublic License for more details.\n\nYou should have received a copy of the GNU Lesser General Public License\nalong with this program.  If not, see \u003chttp://www.gnu.org/licenses/\u003e.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpiran-framework%2Fganjex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpiran-framework%2Fganjex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpiran-framework%2Fganjex/lists"}