/*
* Copyright (C) 2005-2016 Alfresco Software Limited.
*
* This file is part of Alfresco Mobile for Android.
*
* Licensed 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.alfresco.mobile.android.application.managers;
import java.io.File;
import java.util.HashMap;
import org.alfresco.mobile.android.api.model.config.ConfigConstants;
import org.alfresco.mobile.android.api.model.config.ConfigScope;
import org.alfresco.mobile.android.api.model.config.ConfigTypeIds;
import org.alfresco.mobile.android.api.model.config.ViewConfig;
import org.alfresco.mobile.android.api.model.config.ViewGroupConfig;
import org.alfresco.mobile.android.api.services.ConfigService;
import org.alfresco.mobile.android.api.services.impl.LocalConfigServiceImpl;
import org.alfresco.mobile.android.api.services.impl.onpremise.OnPremiseConfigServiceImpl;
import org.alfresco.mobile.android.api.session.AlfrescoSession;
import org.alfresco.mobile.android.application.configuration.model.view.SyncConfigModel;
import org.alfresco.mobile.android.async.LoaderResult;
import org.alfresco.mobile.android.async.configuration.ConfigurationEvent;
import org.alfresco.mobile.android.async.session.RequestSessionEvent;
import org.alfresco.mobile.android.platform.EventBusManager;
import org.alfresco.mobile.android.platform.Manager;
import org.alfresco.mobile.android.platform.accounts.AlfrescoAccount;
import org.alfresco.mobile.android.platform.accounts.AlfrescoAccountManager;
import org.alfresco.mobile.android.platform.io.AlfrescoStorageManager;
import org.alfresco.mobile.android.platform.utils.SessionUtils;
import org.alfresco.mobile.android.sync.SyncContentManager;
import com.squareup.otto.Subscribe;
import android.content.Context;
import android.support.v4.util.LongSparseArray;
import android.text.TextUtils;
public class ConfigManager extends Manager
{
private EventBusManager eventBus;
protected static final Object LOCK = new Object();
protected static Manager mInstance;
private HashMap<Long, ConfigService> currentService = new HashMap<>();
private LongSparseArray<ConfigService> remoteConfigService = new LongSparseArray<>();
private LongSparseArray<ConfigService> customConfigService = new LongSparseArray<>();
private ConfigService embedConfigService;
private String currentProfileId;
// ///////////////////////////////////////////////////////////////////////////
// CONSTRUCTOR
// ///////////////////////////////////////////////////////////////////////////
protected ConfigManager(Context applicationContext)
{
super(applicationContext);
eventBus = EventBusManager.getInstance();
eventBus.register(this);
}
public static ConfigManager getInstance(Context appContext)
{
synchronized (LOCK)
{
if (mInstance == null)
{
mInstance = new ConfigManager(appContext);
}
return (ConfigManager) mInstance;
}
}
public void shutdown()
{
eventBus.unregister(this);
}
// ///////////////////////////////////////////////////////////////////////////
// LIFECYCLE
// ///////////////////////////////////////////////////////////////////////////
/**
* We have 3 different configuration files :
* <ul>
* <li>Embededed : Default and defined by the application</li>
* <li>Custom : Defined by the user</li>
* <li>Remote : Defined by the server</li>
* </ul>
* Priority : Remote always wins ! Then custom then embedded
*
* @param acc
*/
public void init(AlfrescoAccount acc)
{
// Load default embedded configuration
// NB : Since 1.5 embedded configuration is mandatory
if (embedConfigService == null)
{
embedConfigService = new LocalConfigServiceImpl(appContext);
}
// With no account we cant identify the right configuration.
if (acc == null)
{
acc = AlfrescoAccountManager.getInstance(appContext).getDefaultAccount();
}
if (acc == null) { return; }
// Load any remote or cached configuration
try
{
ConfigService configService = loadCached(acc);
if (configService == null)
{
ConfigService customConfigService = loadCustom(acc);
configService = (customConfigService != null) ? customConfigService : embedConfigService;
}
if (SessionUtils.getSession(appContext) != null && configService instanceof LocalConfigServiceImpl)
{
((LocalConfigServiceImpl) configService).setSession(SessionUtils.getSession(appContext));
}
if (configService != null)
{
currentService.put(acc.getId(), configService);
}
// Config is available. Send an event
if (configService.hasViewConfig())
{
eventBus.post(new ConfigurationMenuEvent(acc.getId()));
}
}
catch (Exception e)
{
// Nothing to do
}
}
// ///////////////////////////////////////////////////////////////////////////
// RETRIEVE CONFIGURATION
// ///////////////////////////////////////////////////////////////////////////
public void loadRemote(long accountId, ConfigService service)
{
// Check if the configuration is present
if (service instanceof OnPremiseConfigServiceImpl)
{
remoteConfigService.put(accountId, service);
}
}
public void setSession(long accountId, AlfrescoSession session)
{
if (remoteConfigService != null && remoteConfigService.get(accountId) != null)
{
currentService.put(accountId, remoteConfigService.get(accountId));
}
else if (customConfigService != null && customConfigService.get(accountId) != null)
{
((LocalConfigServiceImpl) customConfigService.get(accountId)).setSession(session);
if (customConfigService.get(accountId) != null)
{
currentService.put(accountId, customConfigService.get(accountId));
}
}
else
{
// We load the default embedded configuration
if (embedConfigService == null)
{
embedConfigService = new LocalConfigServiceImpl(appContext);
}
((LocalConfigServiceImpl) embedConfigService).setSession(session);
if (embedConfigService != null)
{
currentService.put(accountId, embedConfigService);
}
// Horrible hack to reset profile sync activation as its not
// implemented as feature
if (hasSyncView(embedConfigService, "default"))
{
SyncContentManager.getInstance(appContext).setActivateSync(accountId, true);
}
}
currentProfileId = null;
eventBus.post(new ConfigurationMenuEvent(accountId));
}
private ConfigService loadEmbedded()
{
// We load the default embedded configuration
if (embedConfigService == null)
{
embedConfigService = new LocalConfigServiceImpl(appContext);
}
// Set Session explicitly
((LocalConfigServiceImpl) embedConfigService).setSession(SessionUtils.getSession(appContext));
LoaderResult<ConfigService> result = new LoaderResult<ConfigService>();
result.setData(embedConfigService);
EventBusManager.getInstance().post(new ConfigurationEvent("", result, -1));
return embedConfigService;
}
private ConfigService loadCustom(AlfrescoAccount account)
{
// We load the latest custom configuration file defined by the user
File configFolder = AlfrescoStorageManager.getInstance(appContext).getCustomFolder(account);
File configFile = new File(configFolder, ConfigConstants.CONFIG_FILENAME);
// No file == No configuration
if (!configFile.exists()) { return loadEmbedded(); }
ConfigService configService = new LocalConfigServiceImpl(configFolder, configFile);
// Check if the configuration is present
if (((LocalConfigServiceImpl) configService).hasConfiguration())
{
customConfigService.put(account.getId(), configService);
}
else
{
configService = null;
}
return configService;
}
private ConfigService loadCached(AlfrescoAccount account)
{
// We load the latest cached version of application configuration.
File configFolder = AlfrescoStorageManager.getInstance(appContext).getConfigurationFolder(account);
ConfigService configService = new LocalConfigServiceImpl(configFolder);
// Check if the configuration is present
if (((LocalConfigServiceImpl) configService).hasConfiguration())
{
remoteConfigService.put(account.getId(), configService);
}
else
{
configService = null;
}
return configService;
}
// ///////////////////////////////////////////////////////////////////////////
// CONFIG MANAGEMENT
// ///////////////////////////////////////////////////////////////////////////
public ConfigService getConfig(long accountId, ConfigTypeIds id)
{
ConfigService service = getConfig(accountId);
if (service == null) { return null; }
switch (id)
{
case VIEWS:
service = (service.hasViewConfig()) ? service
: ((customConfigService.get(accountId) != null) ? customConfigService.get(accountId)
: embedConfigService);
break;
case FORMS:
service = (service.hasFormConfig()) ? service : embedConfigService;
break;
case CREATION:
service = (service.hasCreationConfig()) ? service : embedConfigService;
break;
case REPOSITORY:
service = (service.getRepositoryConfig() != null) ? service : null;
break;
case FEATURES:
service = (service.getFeatureConfig() != null) ? service : null;
break;
case ACTIONS:
service = (service.hasActionConfig()) ? service : null;
break;
default:
break;
}
return service;
}
public ConfigService getConfig(long accountId)
{
// Double check we use the remote instead of local
if (getRemoteConfig(accountId) != null && currentService != getRemoteConfig(accountId))
{
currentService.put(accountId, remoteConfigService.get(accountId));
}
return (currentService != null) ? currentService.get(accountId) : null;
}
public boolean hasConfig(long accountId)
{
return (currentService != null) && currentService.get(accountId) != null;
}
public ConfigService getEmbeddedConfig()
{
return embedConfigService;
}
public ConfigService getCustomConfig(long accountId)
{
return (customConfigService != null) ? customConfigService.get(accountId) : null;
}
public boolean hasCustomConfig(long accountId)
{
return (customConfigService != null) && customConfigService.get(accountId) != null;
}
public ConfigService getRemoteConfig(long accountId)
{
return (remoteConfigService != null) ? remoteConfigService.get(accountId) : null;
}
public boolean hasRemoteConfig(long accountId)
{
return (remoteConfigService != null) && remoteConfigService.get(accountId) != null;
}
// ///////////////////////////////////////////////////////////////////////////
// RETRIEVE CONFIG
// ///////////////////////////////////////////////////////////////////////////
public boolean swapProfile(AlfrescoAccount acc, String profileId)
{
ConfigService config = getConfig(acc.getId());
currentProfileId = profileId;
if (config.hasViewConfig())
{
eventBus.post(new ConfigurationProfileEvent(acc.getId()));
}
return true;
}
public boolean hasSyncView(long accountId, String profileId)
{
ConfigService config = getConfig(accountId);
return hasSyncView(config, profileId);
}
private boolean hasSyncView(ConfigService config, String profileId)
{
return config.hasViewConfig() && parseViewConfigSearchingSyncView(
config.getViewConfig(config.getProfile(profileId).getRootViewId(), new ConfigScope(profileId)));
}
private boolean parseViewConfigSearchingSyncView(ViewConfig viewConfig) {
if (viewConfig instanceof ViewGroupConfig && ((ViewGroupConfig) viewConfig).getItems().size() > 0) {
for (ViewConfig config : ((ViewGroupConfig) viewConfig).getItems()) {
if (SyncConfigModel.TYPE_ID.equals(config.getType())) {
return true;
}
if (config instanceof ViewGroupConfig && ((ViewGroupConfig) config).getItems().size() > 0) {
parseViewConfigSearchingSyncView(config);
}
}
}
return false;
}
public ConfigScope getCurrentScope()
{
return (TextUtils.isEmpty(currentProfileId)) ? new ConfigScope(null) : new ConfigScope(currentProfileId);
}
public String getCurrentProfileId()
{
return currentProfileId;
}
public void loadAndUseCustom(AlfrescoAccount account)
{
if (loadCustom(account) != null)
{
currentService.put(account.getId(), loadCustom(account));
}
}
public void cleanCache(AlfrescoAccount account)
{
remoteConfigService.remove(account.getId());
}
// ///////////////////////////////////////////////////////////////////////////
// EVENTS
// ///////////////////////////////////////////////////////////////////////////
@Subscribe
public void onConfigContextEvent(ConfigurationEvent event)
{
if (event.hasException || event.data == null) { return; }
if (event.data.hasViewConfig())
{
eventBus.post(new ConfigurationMenuEvent(event.accountId));
}
}
@Subscribe
public void onSessionRequested(RequestSessionEvent event)
{
if (event.accountToLoad == null) { return; }
if (hasConfig(event.accountToLoad.getId()))
{
currentService.remove(event.accountToLoad.getId());
remoteConfigService.remove(event.accountToLoad.getId());
}
}
public static class ConfigurationMenuEvent
{
public final long accountId;
public ConfigurationMenuEvent(long accountId)
{
super();
this.accountId = accountId;
}
}
public static class ConfigurationProfileEvent
{
public final long accountId;
public ConfigurationProfileEvent(long accountId)
{
super();
this.accountId = accountId;
}
}
}