OSGI config edited in repo not applying during runtime | Community
Skip to main content
Level 3
March 2, 2022

OSGI config edited in repo not applying during runtime

  • March 2, 2022
  • 3 replies
  • 3857 views

Hello, I have a servlet that is modifying an osgi config in the repo, which is working as intended and reflecting correctly in crx/de, but the new config is not being reflected in the console until I do a restart, and it isn't taking precedence over the previous config either when I hit the page that it applies to. Is there a way to tell the console to check for this new config? Or something missing in my code? Any help is appreciated!

 

Servlet code:

 

@8220494(service= Servlet.class, property={ Constants.SERVICE_DESCRIPTION + "=Changes the home to maintenance page.", "sling.servlet.methods=" + HttpConstants.METHOD_GET, "sling.servlet.resourceTypes="+ "sling/servlet/default", "sling.servlet.paths=/bin/my/portal-maintenance" }) public class PortalMaintenanceServlet extends SlingAllMethodsServlet { @Reference private ResourceResolverFactory resourceResolverFactory; @Reference PortalConfigHelper portalConfigHelper; @Reference private ConfigurationAdmin configAdmin; private static Logger logger = LoggerFactory.getLogger(PortalMaintenanceServlet.class); /** * Obtains the necessary parameters * * @90521 request the request * @90521 response the response * @throws IOException */ protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) throws IOException{ logger.info("Starting servlet"); ResourceResolver resolver = null; try { Map<String, Object> param = new HashMap<>(); param.put(ResourceResolverFactory.USER, MyConstants.MY_SYSTEM_USER); resolver = resourceResolverFactory.getServiceResourceResolver(param); Map<String, String> reportParams = new HashMap<>(); reportParams.put("publishInstances", StringUtils.join(portalConfigHelper.getPublishDetails(), ';')); String[] publishInstances = reportParams.get("publishInstances").split(";"); try { for(String each : publishInstances) { Jcr2davRepositoryFactory repoFactory = new Jcr2davRepositoryFactory(); String[] publishDetails = each.split("--"); String userName = publishDetails[1].split(":")[0]; String password = publishDetails[1].split(":")[1]; String urlString = String.format("http://%s/crx/server", publishDetails[0]); Map<String, String> params = new HashMap<String, String>(); params.put("org.apache.jackrabbit.repository.uri", urlString); logger.info("trying to connect to repo at: " + publishDetails[0]); Repository repository = repoFactory.getRepository(params); logger.info("logging in to repo"); Session session = repository.login(new SimpleCredentials(userName,password.toCharArray()),"crx.default"); Node root = null; Node contentNode = null; Properties properties = new Properties(); boolean success = false; try { root = session.getRootNode(); contentNode = root.getNode("apps/system/config/com.my.aem.dam.core.configs.PortalConfigHelperImpl.config/jcr:content"); if(contentNode == null){ logger.info("unable to get node"); } logger.info("getting input stream"); InputStream content = contentNode.getProperty("jcr:data").getBinary().getStream(); logger.info("loading content"); properties.load(content); logger.info("setting homepage"); properties.setProperty("homePageUrl", "/content/my-portal/maintenance-page.html"); logger.info("Set homepage to " + properties.getProperty("homePageUrl")); success = true; if(success) { logger.info("saving settings"); ByteArrayOutputStream fileOut = new ByteArrayOutputStream(); properties.store(fileOut, "Maintenance Page"); ByteArrayInputStream is = new ByteArrayInputStream(fileOut.toByteArray()); ValueFactory valueFactory = resolver.adaptTo(Session.class).getValueFactory(); Binary contentValue = valueFactory.createBinary(is); contentNode.setProperty("jcr:data", contentValue); contentValue.dispose(); is.close(); session.save(); fileOut.close(); content.close(); } } catch(Exception e) { System.out.println("Could not set maintenance page" + e); } } }catch (RepositoryException e){ logger.error("Check the permission and the settings of the service user for this service.\n", e); response.sendError(SlingHttpServletResponse.SC_INTERNAL_SERVER_ERROR, MyConstants.MY_SERVER_ERROR + "\n" + e.getMessage()); } } catch (LoginException e) { logger.error("Error while trying to login.\n", e); response.sendError(SlingHttpServletResponse.SC_INTERNAL_SERVER_ERROR, MyConstants.MY_SERVER_ERROR + "\n" + e.getMessage()); if(resolver != null) resolver.close(); } } }
This post is no longer active and is closed to new replies. Need help? Start a new post to ask your question.

3 replies

lukasz-m
Community Advisor
Community Advisor
March 2, 2022

Hi @dnest19, I see you have ConfigurationAdmin object but you are not using it. I think that is the way to go. It will simplify your code a lot. I did quick check on my local instance, you could use code like below:

Configuration config = configAdmin.getConfiguration("com.my.aem.dam.core.configs.PortalConfigHelperImpl");
Dictionary dictionary = config.getProperties();
dictionary.put("homePageUrl", "/content/my-portal/maintenance-page.html");
config.update(dictionary);

In general it will get OSGi configuration for given PID, read current configuration and update it with new value. Configuration is updated and applied immediately - changes can be seen in OSGi console as well. Instance restart is not needed.

If I good understand your code, you are accessing repository of some remote instance from the other instance - I think this approach is over complicated. If you will run your code on each instance separately complexity of your code will decrease significantly, and your servlet could look like that.

@Component(service= Servlet.class,
        property={
                Constants.SERVICE_DESCRIPTION + "=Changes the home to maintenance page.",
                "sling.servlet.methods=" + HttpConstants.METHOD_GET,
                "sling.servlet.resourceTypes="+ "sling/servlet/default",
                "sling.servlet.paths=/bin/my/portal-maintenance"
        })
public class PortalMaintenanceServlet extends SlingAllMethodsServlet {

    @Reference
    private ConfigurationAdmin configAdmin;

    @Override
    protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response)
            throws ServletException, IOException {
        Configuration config = configAdmin
                .getConfiguration("com.my.aem.dam.core.configs.PortalConfigHelperImpl");
        Dictionary dictionary = config.getProperties();
        dictionary.put("homePageUrl", "/content/my-portal/maintenance-page.html");
        config.update(dictionary);
    }
} 

 

DNest19Author
Level 3
March 2, 2022

Yeah that configadmin was leftover from an older version of the code. The reason I'm accessing the repos remotely is that I'm trying to make a button for a tools page on the author instance that changes these settings on two publisher instances. The goal is to give someone other than myself the ability to do this without having to access the system console or crx/de.

lukasz-m
Community Advisor
Community Advisor
March 2, 2022

Ok, I got the case, but I still think that even if you would like to control it from author, then you should go in different direction, e.g.

  • you can expose an endpoint (servlet on each publish server, and by clicking on the button in UI simple sent a request - this will run the logic that will modify OSGi config - of course you can add some additional security layer related to that servlet)
  • or you could use replication, and trigger some action on publish that will be related to that.

Using OSGi API - for config modification in my opinion is the right approach, of course how this will be triggered is a different story.

Jineet_Vora
Community Advisor and Adobe Champion
Community Advisor and Adobe Champion
March 2, 2022

Hi @dnest19, do you have the config stored under /apps/<project_structure>/config? Can you try changing the value there as well and see if the OSGi console is updating the value after making the change?

Jineet

DNest19Author
Level 3
March 2, 2022

I tried that and it doesn't reflect in the console either.

Himanshu_Jain
Community Advisor
Community Advisor
March 3, 2022
DNest19Author
Level 3
March 3, 2022

I found one issue and it was really simple and dumb lol. For some reason this:

 

properties.setProperty("homePageUrl", "/content/my-portal/maintenance-page.html");

 

wasn't actually getting picked up as a string in the datastream. I added a pair of escaped quotes around the url and now it picks up the new string, but only after I manually hit "save all" in crx/de. Is there a way to programmatically perform that action? I thought session.save() should, but that's not working out.

 

properties.setProperty("homePageUrl", "\"/content/my-portal/maintenance-page.html\"");

 

DNest19Author
Level 3
March 4, 2022

Edited my response. I though this had solved the issue, but I still have to hit save all in the repo to get the changes to pick up. Is there a way to perform that action programmatically? I thought session.save() is more or less equivalent, but it doesn't seem to be. 

lukasz-m
Community Advisor
Community Advisor
March 4, 2022

@dnest19, this line could be the root cause of your current problem:

ValueFactory valueFactory = resolver.adaptTo(Session.class).getValueFactory();

You are using local resolver and local session instead of remote session that you have created here:

Session session = repository.login(new SimpleCredentials(userName,password.toCharArray()),"crx.default");

So you could try something like this:

ValueFactory valueFactory = resolver.adaptTo(Session.class).getValueFactory();
// replace with ValueFactory valueFactory = session.getValueFactory();

If this will work then you will not need the resolver and resolver related code at all.