J2EE Profiler integration API

Contents

J2EE Integration Profiler API changes

This document describes the existed J2EE Profiler integration API, proposed API and purpose of change.

Current J2EE Profiler API

The current API consist of several files in j2eeserver module:

Issues with current API/SPI

  • First of all the current API is not an API actually. This is just simple functionality separation. J2EE should not depend from NB profiler. So one need to extract required dependency from Profiler into simple interfaces/classes. As result there is no need to have Profiler installed into the NB at all. So it can work without Profiler ( this is good ). But API should gives the possibility to plug other implementation of Profiler. This is currently is not possible. Current API should be actually just friend packages for NB Profiler module .
  • Previous item mentions the one of the main purpose of API change: give the possibility to plug various Profiler ( from J2EE point of view ).
  • There are several issues which can't be solved with existing API/SPI :
  • Profiler could support several simultaneous sessions.

In the attempt to solve described problems new API/SPI is suggested.

Proposed J2EE Profiler integration API/SPI

  • The problem of several sessions could be solved by extracting Profiler interface functionality into two interfaces : File:ProfilerProvider.java and File:ProfilerSession.java. The first one is entry point of Profiler plugin. ProfilerProvider implementation classes should be declared as service providers (access via lookup). ProfilerSession is 1:1 context for started J2EE profiling session. Session is created each time when J2EE server should be started in profiling mode.
  • State listeners are introduced. This allows to stop server on Profiler stop .
  • ProfilerSupport class is deprecated as result . Its "getState()" method suppose only one Profiler . All its state constants was moved into ProdilerSession interface.

The items above describes structure changes in API/SPI. The following text describes methods from design and usage point of view.

SPI : ProfilerProvider

This is the service provider interface. Each J2EE Profiler plugin needs to implement this interface ( and register in default lookup ).

  • ProfilerServerSettings API class contains information for starting profiling agent. It includes java platform, java arguments and environment variables. These settings are passed from clients which wants to start J2EE server in profiling mode. Such clients are Project and Server Node in Services tab. Project uses Ant task org.netbeans.modules.j2ee.ant.StartProfiledServer which gets previously configured parameters and pass them into ProfilerServerSettings. J2EE Server node uses ProfilerProvider.getDefaultServerSettings(String , boolean ) method to get settings for starting server in Profile mode. This method is result of removing two methods in Profiler : getSettings(String , boolean verbose) and getSettings(String serverInstanceID).
  • Settings are used for getting session via ProfilerProvider.getSession(ProfilerServerSettings ).
  • Method ProfilerProvider.canConfigure(ProfilerSession) is used to determine whether new profiling session could be used for J2EE server starting. Currently NB Profiler doesn't allow to start simultaneously several sessions. So NB Profiler provider implementation is responsible for tracking sessions and should disallow to configure new sessions if there is already session in progress. Other Profilers could allow to start several sessions ( But still we allow just one session per J2EE server. Other session could be used for starting other J2EE server in the same time ). In this case Profiler provider method getSession() should return true .

SPI : ProfilerSession

Contains number of constants which are profiling states . They was moved from ProfilerSupport class.

  • Method ProfilerSession.notifyStarting() uses for notifying Profiler implementation that profiling is started. It can be used by implementation for some initial actions. Please note that real server start is performed outside of J2EE Profiler integration . This is done by J2EE Server plugin provider . Each J2EE server plugin is responsible for starting J2EE server in profile mode ( only this plugin knows how it can be started ). So common J2EE Profiler integration plugin doesn't have any control on starting profiling. This is why notifyStarting() method is used. This method was moved from old Profiler interface.
  • Method ProfilerSession.attachProfiler() is also moved from old Profiler interface. It is used to attach profiler to J2EE target JVM.
  • Method ProfilerSession.getState() is also moved from old Profiler interface. It is used for accessing to state of Profiler agent.
  • Method ProfilerSession.getProvider() return Provider implementation which produced this session.
  • Method ProfilerSession.configureSession() is used for session configuration before it will be started. It is result of requirement to support several profiling sessions. Profiler client ( Project or Server node ) doesn't know anything about current status of Profiling. Client just provides static settings to start profiling. If profiler supports several sessions then such settings could be not enough to start new session. Profiler integration could add or change these settings to be able to start new session.
  • Method ProfilerSession.requestStop() is replacement for shutdown() in old Profiler interface. As was already mentioned profiler has no control on J2EE server . So it doesn't really stop . There can be only method which performs some cleanup actions like notifyStart() method. There is a requirement for requestStop() : it should notify state listeners about changed state . One of such listener is Server Instance node which will call stop server method when it gets "stopping" event.
  • Methods ProfilerSession.addProfilerStateListener( ChangeListener ) and ProfilerSession.removeProfilerStateListener( ChangeListener ) adds and removes profiler state listeners.

SPI : StartServer

This is actually J2EE class which should implement each J2EE server plugin to provide start/stop server functionality. There are only two minor changes in this class:

  • Method StartServer.startProfiling(Target, ProfilerServerSettings , ProfilerSession ) is the same as original method but one additional parameter ProfilerSession is added. It has default implementation so subclasses don't need to implement it mandatory.
  • New method StartServer.supportsProfilerStop() is added with default implementation. Subclasses again don't need to override it. It is used for J2EE servers which wants to perform some additional clean up on stop when server was not really started. There could be a situation when JVM of J2EE server

was started and blocked by Profiling agent. It means that J2EE server is not really started ( main method of main class is not called ). In the latter case generally method StartServer.stopDeploymentManager() should not be called. Implementation of this method usually connects to J2EE server admin port for stopping it. But server was not really started so if method tries to connect to J2EE server port it will fail. Sometimes however J2EE StartServer implementation can require to do some clean up after stopping JVM blocked by Profiling agent . Such server should return true on supportsProfilerStop() method call. In this case StartServer.stopDeploymentManager() will be called even if JVM was blocked by profiling agent.

API : ProfilerServerSettings

This class is a bean with information for profiler agent start . Contains Java platform ( path to java ) , java arguments and environment variables. It is the same as in original API except some changes :

  • Two setters for Java arguments and Environment variables was added. They are could be used by ProfilerSession to modify original client settings ( add some args, ... ). It will allows to start new profiling session even if there is already started session.
  • Bean contains getter for Properties class. This class is used for transferring properties from client ( Project , Service instance node ) to Profiler integration. Also these properties could be used as storage for information between J2EE server plugin and profiler.

API : ProfilerRegistry

  • See class File:ProfilerRegistry.java
  • Different providers can be distinguished via identifier returned by method ProfilerRegistry.getId(ProfilerProvider). NetBeans could have several Profilers installed and only one currently chosen ( f.e. via Preferences ). This currently chosen Profiler will be used by default for project Profiling or starting J2EE server in profiling mode via Services tab. Project could ( this is not necessarily but just possibility ) have configurable Profiler usage. Method ProfilerRegistry.getProvider(String) is used for access to provider by id. The Services tab doesn't have customizer so Services node should use some singleton" Profiler which could be accessed via known Profiler id. NetBeans Preference could give such id. Services node will choose ProfilerProvider via method ProfilerRegistry.getProvider() .

Here is example how current version of ProfilerServerSettings could be used even for NB Profiler :

NB Profiler doesn't allow to start several session . This is limitation of implementation. Project is responsible for providing to Profiler java arguments which should be used to start JVM ( with agent ). Based on provided by Project profiling settings Profiler creates ProfilerServerSettings. Let's method canConfigure() of ProfilerProvider always returns true. Method configureSession() of ProfilerSession should change Agent Port and Agent Id appropriately . As result it should also change java arguments in ProfilerServerSettings . Result of configureSession() method will be used for starting J2EE server in profiling mode with other port which is not occupied. As result several profiling sessions could work simultaneously for several J2EE servers . So current API allows to support several NB Profiling session. The only problem here is NB Profiler implementation which supposed to work in singleton mode.

API Usecases

There are two ways to start J2EE server in profiling mode in IDE (one need care only about IDE management of server):

  • Start server on Profiler project action.
  • Start server in profile mode via Services tab.

The first one is realized now via Ant task org.netbeans.modules.j2ee.ant.StartProfiledServer. See this file updated respectively new API File:StartProfiledServer.java. The second one is AWT Action which implemented by ProfileAction. See this file updated respectively new API File:ProfileAction.java.

The first of all there is an access to ProfilerProvider via ProfilerRegistry.getProfilerProvider( ). Ant task contains optional attribute profilerId which could be passed by Project. This is an identifier of Provider which could be used for Project profiling.

    public ProfilerProvider getProvider( String id ){
        Lookup.Template<ProfilerProvider> templ = new Lookup.Template<ProfilerProvider>(
                ProfilerProvider.class , id , null);
        Iterator<? extends ProfilerProvider> iterator = 
            Lookup.getDefault().lookup(templ).allInstances().iterator();
        if ( iterator.hasNext() ){
            return iterator.next();
        }
        return null;
    }
    
    public ProfilerProvider getProvider(  ){
        Preferences preferences = NbPreferences.forModule( ProfilerProvider.class );
        String id = preferences.get( PROFILER_ID, null );
        if ( id == null ){
            Lookup.Template<ProfilerProvider> templ = new Lookup.Template<ProfilerProvider>(
                    ProfilerProvider.class );
            Lookup.Result<ProfilerProvider> result = Lookup.getDefault().lookup(templ);
            Iterator<? extends Item<ProfilerProvider>> iterator = 
                result.allItems().iterator(); iterator.hasNext(); 
            if ( iterator.hasNext()){
                Item<ProfilerProvider> item = iterator.next();
                return item.getInstance();
            }
            else {
                return null;
            }
        }
        else {
            return getProvider( id );
        }
    }

The next step is ProfilerServerSettings construction. They are instantiated either based on properties passed to Ant task ( when Project start J2EE server profiling ) or via ProfilerProvider.getDefaultServerSettings() ( when server instance is started via Services tab and there are no other known settings for J2EE server ). Profiler provider creates ProfilerSession based on these settings .This session is used as argument for startProfile() method of ServerInstance class. All further J2EE server management is done by ServerInstance class. See here File:ServerInstance.java updated ServerInstance class respectively new API. Method _startProfile() will be called no matter how J2EE server start was requested ( either via Project profile or via Services node action ). You can check its current implementation via link above to proposed ServerInstance class change. Method canConfigure() of Profiler provider is called to check whether session can be configured for starting J2EE server instance in profiling mode. NB Profiler should returns false if there is already active J2EE profiling session. Then session is configured ( f.e. to find network port which should be used for new session start ) and ServerInstance class is added as listener to track profiler state . After this the J2EE server instance is started in profile mode based on session.

Profiling could be stopped in two ways :

  • Stop action of J2EE server node.
  • Stop profile ( now this is stop button in profiler tab ).

Method shutdownProfiler() will be called as result on first one. It contains call session.requestStop();. This method as result should notify profiler state listeners about stopping action. ServerInstance is one of such listeners. As result method stateChanged() will be called which is implemented :

     public void stateChanged( ChangeEvent event ) {
        ProfilerSession session = getProfilerSession();
        if ( session == null ){
            return;
        }
        if ( session.getState() == ProfilerSession.STATE_STOPPING ){
            session.removeProfilerStateListener( this );
        }
        if ( (getStartServer().supportsProfilerStop() || 
                getServerState() == STATE_PROFILING )  
                && session.getState() == ProfilerSession.STATE_STOPPING  )
        {
            ProgressUI progressUI = myProfilerStopUI.get();
            if ( progressUI == null ){
                progressUI = new ProgressUI(NbBundle.getMessage(
                        ServerInstance.class, "MSG_StoppingProfiler", 
                        getDisplayName()), false);
            }
            try {
                doStopServer(progressUI);
            } catch (ServerException ex) {
                String msg = ex.getLocalizedMessage();
                NotifyDescriptor desc = new NotifyDescriptor.Message(msg, 
                        NotifyDescriptor.ERROR_MESSAGE);
                DialogDisplayer.getDefault().notify(desc);
            }
        }
        else {
            refresh();
        }
    }

As result server will be carefully stopped via server scripts .

ProfilerSession will notify its listeners about stopping action when profiler is going to stop. As result stateChanged() method of ServerInstance class will be called again with appropriate stop of J2EE server.

Not logged in. Log in, Register

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2012, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo