From c8b983fb93aced6b0a558037f8ee1cc9d971c3ea Mon Sep 17 00:00:00 2001 From: Gathika94 Date: Thu, 4 Apr 2019 14:02:15 +0530 Subject: [PATCH] Add seperate class to facilitate unit tests related to the LifeCycleManagementTest --- .../mgt/core/impl/ApplicationManagerImpl.java | 14 +++---- ...ApplicationManagementServiceComponent.java | 10 ++--- .../mgt/core/internal/DataHolder.java | 12 +++--- ...Manger.java => LifecycleStateManager.java} | 28 +++++-------- .../core/util/ApplicationManagementUtil.java | 6 +-- .../LifeCycleStateManagerTest.java | 25 ++++++++++++ .../LifecycleManagementTest.java | 40 +++++++++---------- .../src/test/resources/application-mgt.xml | 2 +- .../main/resources/conf/application-mgt.xml | 2 +- 9 files changed, 77 insertions(+), 62 deletions(-) rename components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/lifecycle/{LifecycleStateManger.java => LifecycleStateManager.java} (88%) create mode 100644 components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/test/java/org.wso2.carbon.device.application.mgt.core/LifeCycleStateManagerTest.java diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/impl/ApplicationManagerImpl.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/impl/ApplicationManagerImpl.java index ab34e6b549d..11e7c1380a1 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/impl/ApplicationManagerImpl.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/impl/ApplicationManagerImpl.java @@ -52,7 +52,7 @@ import org.wso2.carbon.device.application.mgt.core.exception.LifeCycleManagement import org.wso2.carbon.device.application.mgt.core.exception.NotFoundException; import org.wso2.carbon.device.application.mgt.core.exception.VisibilityManagementDAOException; import org.wso2.carbon.device.application.mgt.core.internal.DataHolder; -import org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManger; +import org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManager; import org.wso2.carbon.device.application.mgt.core.util.ConnectionManagerUtil; import org.wso2.carbon.device.mgt.common.DeviceManagementException; @@ -77,12 +77,12 @@ public class ApplicationManagerImpl implements ApplicationManager { private ApplicationDAO applicationDAO; private ApplicationReleaseDAO applicationReleaseDAO; private LifecycleStateDAO lifecycleStateDAO; - private LifecycleStateManger lifecycleStateManger; + private LifecycleStateManager lifecycleStateManager; public ApplicationManagerImpl() { initDataAccessObjects(); - lifecycleStateManger = DataHolder.getInstance().getLifecycleStateManager(); + lifecycleStateManager = DataHolder.getInstance().getLifecycleStateManager(); } private void initDataAccessObjects() { @@ -576,7 +576,7 @@ public class ApplicationManagerImpl implements ApplicationManager { LifecycleState appLifecycleState = getLifecycleState(applicationId, applicationRelease.getUuid()); LifecycleState newAppLifecycleState = getLifecycleStateInstant(AppLifecycleState.REMOVED.toString(), appLifecycleState.getCurrentState()); - if (lifecycleStateManger.isValidStateChange(newAppLifecycleState.getPreviousState(), + if (lifecycleStateManager.isValidStateChange(newAppLifecycleState.getPreviousState(), newAppLifecycleState.getCurrentState(),userName,tenantId)) { this.lifecycleStateDAO .addLifecycleState(newAppLifecycleState, applicationId, applicationRelease.getUuid(), @@ -623,7 +623,7 @@ public class ApplicationManagerImpl implements ApplicationManager { LifecycleState newAppLifecycleState = getLifecycleStateInstant(AppLifecycleState.REMOVED.toString(), appLifecycleState.getCurrentState()); String userName = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); - if (lifecycleStateManger.isValidStateChange(newAppLifecycleState.getPreviousState(), + if (lifecycleStateManager.isValidStateChange(newAppLifecycleState.getPreviousState(), newAppLifecycleState.getCurrentState(),userName,tenantId)) { this.lifecycleStateDAO .addLifecycleState(newAppLifecycleState, applicationId, applicationRelease.getUuid(), @@ -949,7 +949,7 @@ public class ApplicationManagerImpl implements ApplicationManager { + releaseUuid); } - lifecycleState.setNextStates(new ArrayList<>(lifecycleStateManger.getNextLifecycleStates(lifecycleState.getCurrentState()))); + lifecycleState.setNextStates(new ArrayList<>(lifecycleStateManager.getNextLifecycleStates(lifecycleState.getCurrentState()))); } catch (ApplicationManagementException e) { throw new ApplicationManagementException("Failed to get application and application management", e); @@ -985,7 +985,7 @@ public class ApplicationManagerImpl implements ApplicationManager { state.setUpdatedBy(userName); if (state.getCurrentState() != null && state.getPreviousState() != null) { - if (lifecycleStateManger.isValidStateChange(state.getPreviousState(), state.getCurrentState(),userName, + if (lifecycleStateManager.isValidStateChange(state.getPreviousState(), state.getCurrentState(),userName, tenantId)) { //todo if current state of the adding lifecycle state is PUBLISHED, need to check whether is there //todo any other application release in PUBLISHED state for the application( i.e for the appid) diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/internal/ApplicationManagementServiceComponent.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/internal/ApplicationManagementServiceComponent.java index 968be5cce7a..d43994edadd 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/internal/ApplicationManagementServiceComponent.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/internal/ApplicationManagementServiceComponent.java @@ -31,7 +31,7 @@ import org.wso2.carbon.device.application.mgt.core.config.ConfigurationManager; import org.wso2.carbon.device.application.mgt.common.config.UIConfiguration; import org.wso2.carbon.device.application.mgt.core.dao.common.ApplicationManagementDAOFactory; import org.wso2.carbon.device.application.mgt.core.impl.ConfigManagerImpl; -import org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManger; +import org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManager; import org.wso2.carbon.device.application.mgt.core.lifecycle.config.LifecycleState; import org.wso2.carbon.device.application.mgt.core.util.ApplicationManagementUtil; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; @@ -79,10 +79,10 @@ public class ApplicationManagementServiceComponent { List lifecycleStates = ConfigurationManager.getInstance(). getConfiguration().getLifecycleStates(); - LifecycleStateManger lifecycleStateManger = ApplicationManagementUtil.getLifecycleStateMangerInstance(); - lifecycleStateManger.init(lifecycleStates); - DataHolder.getInstance().setLifecycleStateManger(lifecycleStateManger); - bundleContext.registerService(LifecycleStateManger.class.getName(), lifecycleStateManger, null); + LifecycleStateManager lifecycleStateManager = ApplicationManagementUtil.getLifecycleStateMangerInstance(); + lifecycleStateManager.init(lifecycleStates); + DataHolder.getInstance().setLifecycleStateManger(lifecycleStateManager); + bundleContext.registerService(LifecycleStateManager.class.getName(), lifecycleStateManager, null); ApplicationManager applicationManager = ApplicationManagementUtil.getApplicationManagerInstance(); DataHolder.getInstance().setApplicationManager(applicationManager); diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/internal/DataHolder.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/internal/DataHolder.java index cd43186dc8a..e16d0aea5cf 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/internal/DataHolder.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/internal/DataHolder.java @@ -23,7 +23,7 @@ import org.wso2.carbon.device.application.mgt.common.services.ApplicationStorage import org.wso2.carbon.device.application.mgt.common.services.ConfigManager; import org.wso2.carbon.device.application.mgt.common.services.ReviewManager; import org.wso2.carbon.device.application.mgt.common.services.SubscriptionManager; -import org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManger; +import org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManager; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; import org.wso2.carbon.user.core.service.RealmService; @@ -44,7 +44,7 @@ public class DataHolder { private ApplicationStorageManager applicationStorageManager; - private LifecycleStateManger lifecycleStateManger; + private LifecycleStateManager lifecycleStateManager; private ConfigManager configManager; @@ -106,12 +106,12 @@ public class DataHolder { return applicationStorageManager; } - public LifecycleStateManger getLifecycleStateManager() { - return lifecycleStateManger; + public LifecycleStateManager getLifecycleStateManager() { + return lifecycleStateManager; } - public void setLifecycleStateManger(LifecycleStateManger lifecycleStateManger) { - this.lifecycleStateManger = lifecycleStateManger; + public void setLifecycleStateManger(LifecycleStateManager lifecycleStateManager) { + this.lifecycleStateManager = lifecycleStateManager; } public ConfigManager getConfigManager() { diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/lifecycle/LifecycleStateManger.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/lifecycle/LifecycleStateManager.java similarity index 88% rename from components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/lifecycle/LifecycleStateManger.java rename to components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/lifecycle/LifecycleStateManager.java index 4e443d85de8..9170cbcaa78 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/lifecycle/LifecycleStateManger.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/lifecycle/LifecycleStateManager.java @@ -55,10 +55,10 @@ import java.util.Set; /** * This class represents the activities related to lifecycle management */ -public class LifecycleStateManger { +public class LifecycleStateManager { private Map lifecycleStates; - private static Log log = LogFactory.getLog(LifecycleStateManger.class); + private static Log log = LogFactory.getLog(LifecycleStateManager.class); public void init(List states) throws LifecycleManagementException { lifecycleStates = new HashMap<>(); @@ -80,17 +80,6 @@ public class LifecycleStateManger { } } - public void initializeLifeCycleDetails(List states){ - lifecycleStates = new HashMap<>(); - for (LifecycleState s : states) { - if (s.getProceedingStates() != null) { - s.getProceedingStates().replaceAll(String::toUpperCase); - } - lifecycleStates.put(s.getName().toUpperCase(), new State(s.getName().toUpperCase(), - s.getProceedingStates(), s.getPermission(), s.isAppUpdatable(), s.isAppInstallable(), - s.isInitialState(), s.isEndState())); - } - } public Set getNextLifecycleStates(String currentLifecycleState) { return lifecycleStates.get(currentLifecycleState.toUpperCase()).getProceedingStates(); @@ -136,7 +125,6 @@ public class LifecycleStateManger { if (pair.getKey().toString().equalsIgnoreCase(currentState)) { return lifecycleStates.get(pair.getKey().toString()); } - //it.remove(); } return null; } @@ -165,19 +153,23 @@ public class LifecycleStateManger { return null; } - public boolean isUpdatable(String state){ + public boolean isUpdatable(String state) { State currentState = getMatchingState(state); - if(currentState.getIsAppUpdatable()){ + if (currentState.getIsAppUpdatable()) { return true; } return false; } - public boolean isInstallable(String state){ + public boolean isInstallable(String state) { State currentState = getMatchingState(state); - if(currentState.getIsAppInstallable()){ + if (currentState.getIsAppInstallable()) { return true; } return false; } + + public void setLifecycleStates(Map lifecycleStates) { + this.lifecycleStates = lifecycleStates; + } } diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/util/ApplicationManagementUtil.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/util/ApplicationManagementUtil.java index 0f0901f0b16..3d3da35b870 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/util/ApplicationManagementUtil.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/util/ApplicationManagementUtil.java @@ -27,7 +27,7 @@ import org.wso2.carbon.device.application.mgt.common.services.ReviewManager; import org.wso2.carbon.device.application.mgt.common.services.SubscriptionManager; import org.wso2.carbon.device.application.mgt.core.config.ConfigurationManager; import org.wso2.carbon.device.application.mgt.core.config.Extension; -import org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManger; +import org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManager; import java.lang.reflect.Constructor; @@ -64,10 +64,10 @@ public class ApplicationManagementUtil { return getInstance(extension, ApplicationStorageManager.class); } - public static LifecycleStateManger getLifecycleStateMangerInstance() throws InvalidConfigurationException { + public static LifecycleStateManager getLifecycleStateMangerInstance() throws InvalidConfigurationException { ConfigurationManager configurationManager = ConfigurationManager.getInstance(); Extension extension = configurationManager.getExtension(Extension.Name.LifecycleStateManager); - return getInstance(extension, LifecycleStateManger.class); + return getInstance(extension, LifecycleStateManager.class); } private static T getInstance(Extension extension, Class cls) throws InvalidConfigurationException { diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/test/java/org.wso2.carbon.device.application.mgt.core/LifeCycleStateManagerTest.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/test/java/org.wso2.carbon.device.application.mgt.core/LifeCycleStateManagerTest.java new file mode 100644 index 00000000000..7dbbfe33043 --- /dev/null +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/test/java/org.wso2.carbon.device.application.mgt.core/LifeCycleStateManagerTest.java @@ -0,0 +1,25 @@ +package org.wso2.carbon.device.application.mgt.core; + +import org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManager; +import org.wso2.carbon.device.application.mgt.core.lifecycle.State; +import org.wso2.carbon.device.application.mgt.core.lifecycle.config.LifecycleState; + +import java.util.HashMap; +import java.util.List; + + +public class LifeCycleStateManagerTest extends LifecycleStateManager { + + public void initializeLifeCycleDetails(List states) { + HashMap lifecycleStates = new HashMap<>(); + for (LifecycleState s : states) { + if (s.getProceedingStates() != null) { + s.getProceedingStates().replaceAll(String::toUpperCase); + } + lifecycleStates.put(s.getName().toUpperCase(), new State(s.getName().toUpperCase(), + s.getProceedingStates(), s.getPermission(), s.isAppUpdatable(), s.isAppInstallable(), + s.isInitialState(), s.isEndState())); + } + setLifecycleStates(lifecycleStates); + } +} diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/test/java/org.wso2.carbon.device.application.mgt.core/LifecycleManagementTest.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/test/java/org.wso2.carbon.device.application.mgt.core/LifecycleManagementTest.java index bd02db0bb77..7082f29b74b 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/test/java/org.wso2.carbon.device.application.mgt.core/LifecycleManagementTest.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/test/java/org.wso2.carbon.device.application.mgt.core/LifecycleManagementTest.java @@ -6,7 +6,7 @@ import org.testng.annotations.Test; import org.wso2.carbon.device.application.mgt.common.exception.LifecycleManagementException; import org.wso2.carbon.device.application.mgt.core.config.Configuration; import org.wso2.carbon.device.application.mgt.core.config.ConfigurationManager; -import org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManger; +import org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManager; import org.wso2.carbon.device.application.mgt.core.lifecycle.config.LifecycleState; import java.util.List; @@ -15,72 +15,70 @@ import java.util.Set; public class LifecycleManagementTest { private List lifecycleStates; - private LifecycleStateManger lifecycleStateManger; + private LifecycleStateManager lifecycleStateManager; private final String CURRENT_STATE = "Approved"; private final String NEXT_STATE = "Published"; private final String BOGUS_STATE = "Removed"; private final String UPDATABLE_STATE = "Created"; - private final String NON_UPDATABLE_STATE= "Removed"; + private final String NON_UPDATABLE_STATE = "Removed"; private final String INSTALLABLE_STATE = "Published"; private final String UNINSTALlABLE_STATE = "Removed"; - @BeforeClass public void init() throws LifecycleManagementException { ConfigurationManager configurationManager = ConfigurationManager.getInstance(); Configuration configuration = configurationManager.getConfiguration(); lifecycleStates = configuration.getLifecycleStates(); - lifecycleStateManger = new LifecycleStateManger(); - lifecycleStateManger.initializeLifeCycleDetails(lifecycleStates); + lifecycleStateManager = new LifeCycleStateManagerTest(); + ((LifeCycleStateManagerTest) lifecycleStateManager).initializeLifeCycleDetails(lifecycleStates); } - @Test + @Test public void checkValidNextLifecycleState() { - Set proceedingStates = lifecycleStateManger.getNextLifecycleStates(CURRENT_STATE); + Set proceedingStates = lifecycleStateManager.getNextLifecycleStates(CURRENT_STATE); Assert.assertTrue("Invalid proceeding state of: " + CURRENT_STATE, - proceedingStates.contains(NEXT_STATE.toUpperCase())); + proceedingStates.contains(NEXT_STATE.toUpperCase())); } @Test public void checkInvalidNextLifecycleState() { - Set proceedingStates = lifecycleStateManger.getNextLifecycleStates(CURRENT_STATE); + Set proceedingStates = lifecycleStateManager.getNextLifecycleStates(CURRENT_STATE); Assert.assertFalse("Invalid proceeding state of: " + CURRENT_STATE, - proceedingStates.contains(BOGUS_STATE.toUpperCase())); + proceedingStates.contains(BOGUS_STATE.toUpperCase())); } @Test public void CheckUpdatableState() { - Boolean isUpdatable = lifecycleStateManger.isUpdatable(UPDATABLE_STATE); + Boolean isUpdatable = lifecycleStateManager.isUpdatable(UPDATABLE_STATE); System.out.println(isUpdatable); Assert.assertTrue("Updatable state: " + UPDATABLE_STATE, isUpdatable); } - @Test + @Test public void CheckNonUpdatableState() { - Boolean isUpdatable = lifecycleStateManger.isUpdatable(NON_UPDATABLE_STATE); - Assert.assertFalse("Non Updatable state: " + CURRENT_STATE, isUpdatable); + Boolean isUpdatable = lifecycleStateManager.isUpdatable(NON_UPDATABLE_STATE); + Assert.assertFalse("Non Updatable state: " + NON_UPDATABLE_STATE, isUpdatable); } @Test public void CheckInstallableState() { - Boolean isInstallable = lifecycleStateManger.isInstallable(INSTALLABLE_STATE); - Assert.assertTrue("Installable state: " + INSTALLABLE_STATE,isInstallable); + Boolean isInstallable = lifecycleStateManager.isInstallable(INSTALLABLE_STATE); + Assert.assertTrue("Installable state: " + INSTALLABLE_STATE, isInstallable); } @Test public void CheckUnInstallableState() { - Boolean isInstallable = lifecycleStateManger.isInstallable(UNINSTALlABLE_STATE); - Assert.assertFalse("UnInstallable state: " + UNINSTALlABLE_STATE,isInstallable); + Boolean isInstallable = lifecycleStateManager.isInstallable(UNINSTALlABLE_STATE); + Assert.assertFalse("UnInstallable state: " + UNINSTALlABLE_STATE, isInstallable); } @Test public void check() { - Set proceedingStates = lifecycleStateManger.getNextLifecycleStates(CURRENT_STATE); + Set proceedingStates = lifecycleStateManager.getNextLifecycleStates(CURRENT_STATE); Assert.assertFalse("Invalid proceeding state of: " + CURRENT_STATE, proceedingStates.contains(BOGUS_STATE.toUpperCase())); } - } diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/test/resources/application-mgt.xml b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/test/resources/application-mgt.xml index c14d455efab..01086607d17 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/test/resources/application-mgt.xml +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/test/resources/application-mgt.xml @@ -29,7 +29,7 @@ org.wso2.carbon.device.application.mgt.core.impl.ReviewManagerImpl - org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManger + org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManager org.wso2.carbon.device.application.mgt.core.impl.SubscriptionManagerImpl diff --git a/features/application-mgt/org.wso2.carbon.device.application.mgt.server.feature/src/main/resources/conf/application-mgt.xml b/features/application-mgt/org.wso2.carbon.device.application.mgt.server.feature/src/main/resources/conf/application-mgt.xml index c14d455efab..01086607d17 100644 --- a/features/application-mgt/org.wso2.carbon.device.application.mgt.server.feature/src/main/resources/conf/application-mgt.xml +++ b/features/application-mgt/org.wso2.carbon.device.application.mgt.server.feature/src/main/resources/conf/application-mgt.xml @@ -29,7 +29,7 @@ org.wso2.carbon.device.application.mgt.core.impl.ReviewManagerImpl - org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManger + org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManager org.wso2.carbon.device.application.mgt.core.impl.SubscriptionManagerImpl