Refactor the source:

4.x.x
lasanthaDLPDS 6 years ago
parent 4562432509
commit b0520ac976

@ -24,7 +24,6 @@ import io.swagger.annotations.ApiModelProperty;
import java.util.List;
@ApiModel(value = "Application", description = "Application represents the an Application in Application Store")
public class Application {

@ -177,7 +177,6 @@ public class ApplicationRelease {
this.price = price;
}
public String getAppHashValue() {
return appHashValue;
}

@ -18,8 +18,6 @@
*/
package org.wso2.carbon.device.application.mgt.common;
import com.google.gson.Gson;
import java.io.Serializable;
/**

@ -1,85 +0,0 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.wso2.carbon.device.application.mgt.common;
//TODO
/**
* FilterProperty defines the property that can be used to filter the Application.
*/
public class FilterProperty {
/**
* Operators that can be used in search.
*/
public enum Operator {
EQUALS ("="),
GRATER_THAN (">"),
GREATER_THAN_AND_EQUAL(">="),
LESS_THAN ("<"),
LESS_THAN_AND_EQUAL ("<=");
private final String value;
Operator(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
public FilterProperty(String key, Operator operator, String value) {
this.key = key;
this.operator = operator;
this.value = value;
}
private String key;
private Operator operator;
private String value;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public Operator getOperator() {
return operator;
}
public void setOperator(Operator operator) {
this.operator = operator;
}
}

@ -1,34 +0,0 @@
package org.wso2.carbon.device.application.mgt.common;
/**
* This represents the LifeCycleStateTransition from one state to next state.
*/
public class LifecycleStateTransition {
private String nextState;
private String permission;
private String description;
public String getNextState() {
return nextState;
}
public String getPermission() {
return permission;
}
public String getDescription() {
return description;
}
public void setNextState(String nextState) {
this.nextState = nextState;
}
public void setPermission(String permission) {
this.permission = permission;
}
public void setDescription(String description) {
this.description = description;
}
}

@ -1,53 +0,0 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.wso2.carbon.device.application.mgt.common;
/**
* Represents the payment related information for the {@link Application}.
*/
public class Payment {
private boolean freeApp;
private String paymentCurrency;
private float paymentPrice;
public boolean isFreeApp() {
return freeApp;
}
public void setFreeApp(boolean freeApp) {
this.freeApp = freeApp;
}
public String getPaymentCurrency() {
return paymentCurrency;
}
public void setPaymentCurrency(String paymentCurrency) {
this.paymentCurrency = paymentCurrency;
}
public float getPaymentPrice() {
return paymentPrice;
}
public void setPaymentPrice(float paymentPrice) {
this.paymentPrice = paymentPrice;
}
}

@ -1,77 +0,0 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.wso2.carbon.device.application.mgt.common;
import java.util.Date;
/**
* Represents subscription of an {@link Application}
*/
public class Subscription {
private Visibility.Type type;
private String value;
private Date createdAt;
private Application application;
private ApplicationRelease applicationRelease;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public Visibility.Type getType() {
return type;
}
public void setType(Visibility.Type type) {
this.type = type;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public Application getApplication() {
return application;
}
public void setApplication(Application application) {
this.application = application;
}
public ApplicationRelease getApplicationRelease() {
return applicationRelease;
}
public void setApplicationRelease(ApplicationRelease applicationRelease) {
this.applicationRelease = applicationRelease;
}
}

@ -1,54 +0,0 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.wso2.carbon.device.application.mgt.common;
import java.util.List;
/**
* This class represents the visibility details of an Application.
*/
public class Visibility {
private Type type;
private List<String> allowedList;
public Type getType() {
return type;
}
public void setType(Type type) {
this.type = type;
}
public List<String> getAllowedList() {
return allowedList;
}
public void setAllowedList(List<String> allowedList) {
this.allowedList = allowedList;
}
/**
* Type of the visibility of the application.
*/
public enum Type {
PUBLIC, ROLES, DEVICE_GROUPS
}
}

@ -23,10 +23,8 @@ import org.wso2.carbon.device.application.mgt.common.ApplicationList;
import org.wso2.carbon.device.application.mgt.common.ApplicationRelease;
import org.wso2.carbon.device.application.mgt.common.Filter;
import org.wso2.carbon.device.application.mgt.common.LifecycleState;
import org.wso2.carbon.device.application.mgt.common.LifecycleStateTransition;
import org.wso2.carbon.device.application.mgt.common.UnrestrictedRole;
import org.wso2.carbon.device.application.mgt.common.exception.ApplicationManagementException;
import org.wso2.carbon.device.application.mgt.common.exception.LifecycleManagementException;
import java.util.List;

@ -1,59 +0,0 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.wso2.carbon.device.application.mgt.common.services;
import org.wso2.carbon.device.application.mgt.common.UnrestrictedRole;
import org.wso2.carbon.device.application.mgt.common.Visibility;
import org.wso2.carbon.device.application.mgt.common.exception.VisibilityManagementException;
import java.util.List;
/**
* This interface manages all the operations related with Application Visibility.
* This will be invoking the necessary backend calls for the data bases layer
* and provide the functional implementation.
*/
public interface UnrestrictedRoleManager {
/**
* Add (if there is no visibility configuration for the application) or
* Update (if there is already existing configuration for the application)
* the visibility related configuration for the application
*
* @param applicationID The ID of the application
* @param visibility The visibility configuration for the particular application.
*/
Visibility put(int applicationID, Visibility visibility) throws VisibilityManagementException;
/**
* Returns the Visibility configuration of the provided applicationUUID.
*
* @param applicationID The ID of the application
* @param tenantId tenant Id
* @return Visibility configuration
*/
List<UnrestrictedRole> getUnrestrictedRoles(int applicationID, int tenantId) throws VisibilityManagementException;
/**
* Remove the visibility configuration mapping for the provided application.
*
* @param applicationID The ID of the application
*/
void remove(int applicationID) throws VisibilityManagementException;
}

@ -1,117 +0,0 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.wso2.carbon.device.application.mgt.core.impl;
import org.wso2.carbon.device.application.mgt.common.UnrestrictedRole;
import org.wso2.carbon.device.application.mgt.common.Visibility;
import org.wso2.carbon.device.application.mgt.common.exception.ApplicationManagementException;
import org.wso2.carbon.device.application.mgt.common.exception.VisibilityManagementException;
import org.wso2.carbon.device.application.mgt.common.services.UnrestrictedRoleManager;
import org.wso2.carbon.device.application.mgt.core.dao.VisibilityDAO;
import org.wso2.carbon.device.application.mgt.core.dao.common.ApplicationManagementDAOFactory;
import org.wso2.carbon.device.application.mgt.core.util.ConnectionManagerUtil;
import java.util.Collection;
import java.util.List;
//todo need to work on business logic
/**
* This is the default implementation for the visibility manager.
*/
public class UnrestrictedRoleManagerImpl implements UnrestrictedRoleManager {
@Override
public Visibility put(int applicationID, Visibility visibility) throws VisibilityManagementException {
return null;
// if (visibility == null) {
// visibility = new Visibility();
// visibility.setType(Visibility.Type.PUBLIC);
// }
// if (visibility.getAllowedList() == null && !visibility.getType().equals(Visibility.Type.PUBLIC)) {
// throw new VisibilityManagementException("Visibility is configured for '" + visibility.getType()
// + "' but doesn't have any allowed list provided!");
// }
// boolean isTransactionStarted = false;
// try {
// isTransactionStarted = ConnectionManagerUtil.isTransactionStarted();
// if (!isTransactionStarted) {
// ConnectionManagerUtil.beginDBTransaction();
// }
// VisibilityDAO visibilityDAO = ApplicationManagementDAOFactory.getVisibilityDAO();
// int visibilityTypeId = visibilityDAO.getVisibilityID(visibility.getType());
// visibilityDAO.delete(applicationID);
// visibilityDAO.add(applicationID, visibilityTypeId, visibility.getAllowedList());
// if (!isTransactionStarted) {
// ConnectionManagerUtil.commitDBTransaction();
// }
// return visibility;
// } catch (ApplicationManagementException e) {
// if (!isTransactionStarted) {
// ConnectionManagerUtil.rollbackDBTransaction();
// }
// throw new VisibilityManagementException("Problem occured when trying to fetch the application with ID - "
// + applicationID, e);
// } finally {
// if (!isTransactionStarted) {
// ConnectionManagerUtil.closeDBConnection();
// }
// }
}
@Override
public List<UnrestrictedRole> getUnrestrictedRoles(int applicationID, int tenantId) throws VisibilityManagementException {
try {
VisibilityDAO visibilityDAO = ApplicationManagementDAOFactory.getVisibilityDAO();
List<UnrestrictedRole> unrestrictedRoles = visibilityDAO.getUnrestrictedRoles(applicationID, tenantId);
if (unrestrictedRoles == null) {
return null;
}
return unrestrictedRoles;
} catch (ApplicationManagementException e) {
throw new VisibilityManagementException("Problem occured when trying to fetch the application with ID - "
+ applicationID, e);
}
}
@Override
public void remove(int applicationID) throws VisibilityManagementException {
// boolean isTransactionStarted = false;
// try {
// isTransactionStarted = ConnectionManagerUtil.isTransactionStarted();
// if (!isTransactionStarted) {
// ConnectionManagerUtil.beginDBTransaction();
// }
// VisibilityDAO visibilityDAO = ApplicationManagementDAOFactory.getVisibilityDAO();
// visibilityDAO.delete(applicationID);
// if (!isTransactionStarted) {
// ConnectionManagerUtil.commitDBTransaction();
// }
// } catch (ApplicationManagementException e) {
// if (!isTransactionStarted) {
// ConnectionManagerUtil.rollbackDBTransaction();
// }
// throw new VisibilityManagementException("Problem occurred when trying to fetch the application with ID - "
// + applicationID, e);
// } finally {
// if (!isTransactionStarted) {
// ConnectionManagerUtil.closeDBConnection();
// }
// }
}
}

@ -22,15 +22,12 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.framework.BundleContext;
import org.osgi.service.component.ComponentContext;
import org.wso2.carbon.device.application.mgt.common.exception.InvalidConfigurationException;
import org.wso2.carbon.device.application.mgt.common.services.ApplicationManager;
import org.wso2.carbon.device.application.mgt.common.services.ApplicationStorageManager;
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.common.services.UnrestrictedRoleManager;
import org.wso2.carbon.device.application.mgt.core.config.ConfigurationManager;
import org.wso2.carbon.device.application.mgt.core.dao.common.ApplicationManagementDAOFactory;
import org.wso2.carbon.device.application.mgt.core.exception.ApplicationManagementDAOException;
import org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManger;
import org.wso2.carbon.device.application.mgt.core.lifecycle.config.LifecycleState;
import org.wso2.carbon.device.application.mgt.core.util.ApplicationManagementUtil;
@ -38,7 +35,6 @@ import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.ndatasource.core.DataSourceService;
import org.wso2.carbon.user.core.service.RealmService;
import javax.naming.NamingException;
import java.util.List;
/**
@ -90,10 +86,6 @@ public class ApplicationManagementServiceComponent {
DataHolder.getInstance().setSubscriptionManager(subscriptionManager);
bundleContext.registerService(SubscriptionManager.class.getName(), subscriptionManager, null);
UnrestrictedRoleManager unrestrictedRoleManager = ApplicationManagementUtil.getVisibilityManagerInstance();
DataHolder.getInstance().setVisibilityManager(unrestrictedRoleManager);
bundleContext.registerService(UnrestrictedRoleManager.class.getName(), unrestrictedRoleManager, null);
ApplicationStorageManager applicationStorageManager = ApplicationManagementUtil
.getApplicationStorageManagerInstance();
DataHolder.getInstance().setApplicationStorageManager(applicationStorageManager);

@ -22,7 +22,6 @@ import org.wso2.carbon.device.application.mgt.common.services.ApplicationManager
import org.wso2.carbon.device.application.mgt.common.services.ApplicationStorageManager;
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.common.services.UnrestrictedRoleManager;
import org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManger;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.user.core.service.RealmService;
@ -42,8 +41,6 @@ public class DataHolder {
private SubscriptionManager subscriptionManager;
private UnrestrictedRoleManager unrestrictedRoleManager;
private ApplicationStorageManager applicationStorageManager;
private LifecycleStateManger lifecycleStateManger;
@ -90,14 +87,6 @@ public class DataHolder {
this.subscriptionManager = subscriptionManager;
}
public UnrestrictedRoleManager getVisibilityManager() {
return unrestrictedRoleManager;
}
public void setVisibilityManager(UnrestrictedRoleManager unrestrictedRoleManager) {
this.unrestrictedRoleManager = unrestrictedRoleManager;
}
public RealmService getRealmService() {
return realmService;
}

@ -26,9 +26,6 @@ public class LifecycleStateManger {
}
public boolean isValidStateChange(String currentState, String nextState) {
if (lifecycleStates.get(currentState).getProceedingStates().contains(nextState)) {
return true;
}
return false;
return lifecycleStates.get(currentState).getProceedingStates().contains(nextState);
}
}

@ -25,7 +25,6 @@ import org.wso2.carbon.device.application.mgt.common.services.ApplicationManager
import org.wso2.carbon.device.application.mgt.common.services.ApplicationStorageManager;
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.common.services.UnrestrictedRoleManager;
import org.wso2.carbon.device.application.mgt.core.config.ConfigurationManager;
import org.wso2.carbon.device.application.mgt.core.config.Extension;
@ -51,12 +50,6 @@ public class ApplicationManagementUtil {
return getInstance(extension, ReviewManager.class);
}
public static UnrestrictedRoleManager getVisibilityManagerInstance() throws InvalidConfigurationException {
ConfigurationManager configurationManager = ConfigurationManager.getInstance();
Extension extension = configurationManager.getExtension(Extension.Name.VisibilityManager);
return getInstance(extension, UnrestrictedRoleManager.class);
}
public static SubscriptionManager getSubscriptionManagerInstance() throws InvalidConfigurationException {
ConfigurationManager configurationManager = ConfigurationManager.getInstance();
Extension extension = configurationManager.getExtension(Extension.Name.SubscriptionManager);

@ -23,39 +23,18 @@
<DatasourceName>jdbc/APPM_DS</DatasourceName>
<Extensions>
<Extension name="ApplicationUploadManager">
<ClassName>org.wso2.carbon.device.application.mgt.core.impl.ApplicationUploadManagerImpl</ClassName>
<Parameters>
<Parameter name="UploadPath">repository/resources/mobileapps</Parameter>
</Parameters>
</Extension>
<Extension name="ApplicationManager">
<ClassName>org.wso2.carbon.device.application.mgt.core.impl.ApplicationManagerImpl</ClassName>
</Extension>
<Extension name="ApplicationReleaseManager">
<ClassName>org.wso2.carbon.device.application.mgt.core.impl.ApplicationReleaseManagerImpl</ClassName>
</Extension>
<Extension name="CategoryManager">
<ClassName>org.wso2.carbon.device.application.mgt.core.impl.CategoryManagerImpl</ClassName>
</Extension>
<Extension name="CommentsManager">
<Extension name="ReviewManager">
<ClassName>org.wso2.carbon.device.application.mgt.core.impl.ReviewManagerImpl</ClassName>
</Extension>
<Extension name="LifecycleStateManager">
<ClassName>org.wso2.carbon.device.application.mgt.core.impl.LifecycleStateManagerImpl</ClassName>
</Extension>
<Extension name="PlatformManager">
<ClassName>org.wso2.carbon.device.application.mgt.core.impl.PlatformManagerImpl</ClassName>
<ClassName>org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManger</ClassName>
</Extension>
<Extension name="SubscriptionManager">
<ClassName>org.wso2.carbon.device.application.mgt.core.impl.SubscriptionManagerImpl</ClassName>
</Extension>
<Extension name="VisibilityManager">
<ClassName>org.wso2.carbon.device.application.mgt.core.impl.UnrestrictedRoleManagerImpl</ClassName>
</Extension>
<Extension name="VisibilityTypeManager">
<ClassName>org.wso2.carbon.device.application.mgt.core.impl.VisibilityTypeManagerImpl</ClassName>
</Extension>
</Extensions>
<LifecycleStates>

@ -37,7 +37,6 @@ public class APIUtil {
private static ApplicationManager applicationManager;
private static ApplicationStorageManager applicationStorageManager;
private static SubscriptionManager subscriptionManager;
private static UnrestrictedRoleManager unrestrictedRoleManager;
public static ApplicationManager getApplicationManager() {
if (applicationManager == null) {
@ -116,26 +115,4 @@ public class APIUtil {
return subscriptionManager;
}
/**
* To get the Unrestricted Role manager from the osgi context.
* @return Unrestricted Role manager instance in the current osgi context.
*/
public static UnrestrictedRoleManager getUnrestrictedRoleManager() {
if (unrestrictedRoleManager == null) {
synchronized (APIUtil.class) {
if (unrestrictedRoleManager == null) {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
unrestrictedRoleManager =
(UnrestrictedRoleManager) ctx.getOSGiService(UnrestrictedRoleManager.class, null);
if (unrestrictedRoleManager == null) {
String msg = "Subscription Manager service has not initialized.";
log.error(msg);
throw new IllegalStateException(msg);
}
}
}
}
return unrestrictedRoleManager;
}
}

@ -25,27 +25,15 @@
<Extension name="ApplicationManager">
<ClassName>org.wso2.carbon.device.application.mgt.core.impl.ApplicationManagerImpl</ClassName>
</Extension>
<Extension name="ApplicationReleaseManager">
<ClassName>org.wso2.carbon.device.application.mgt.core.impl.ApplicationReleaseManagerImpl</ClassName>
</Extension>
<Extension name="CategoryManager">
<ClassName>org.wso2.carbon.device.application.mgt.core.impl.CategoryManagerImpl</ClassName>
</Extension>
<Extension name="ReviewManager">
<ClassName>org.wso2.carbon.device.application.mgt.core.impl.ReviewManagerImpl</ClassName>
</Extension>
<Extension name="LifecycleStateManager">
<ClassName>org.wso2.carbon.device.application.mgt.core.impl.LifecycleStateManagerImpl</ClassName>
</Extension>
<Extension name="PlatformManager">
<ClassName>org.wso2.carbon.device.application.mgt.core.impl.PlatformManagerImpl</ClassName>
<ClassName>org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManger</ClassName>
</Extension>
<Extension name="SubscriptionManager">
<ClassName>org.wso2.carbon.device.application.mgt.core.impl.SubscriptionManagerImpl</ClassName>
</Extension>
<Extension name="VisibilityManager">
<ClassName>org.wso2.carbon.device.application.mgt.core.impl.UnrestrictedRoleManagerImpl</ClassName>
</Extension>
<Extension name="ApplicationStorageManager">
<ClassName>org.wso2.carbon.device.application.mgt.core.impl.ApplicationStorageManagerImpl</ClassName>
<Parameters>
@ -53,12 +41,6 @@
<Parameter name="MaxScreenShotCount">6</Parameter>
</Parameters>
</Extension>
<Extension name="PlatformStorageManager">
<ClassName>org.wso2.carbon.device.application.mgt.core.impl.PlatformStorageManagerImpl</ClassName>
<Parameters>
<Parameter name="StoragePath">repository/resources/platforms</Parameter>
</Parameters>
</Extension>
</Extensions>
<!-- This is for publisher lifecycle -->

Loading…
Cancel
Save