Java tutorial
/** * This file is part of Port@l * Port@l 3.0 - Portal Engine and Management System * Copyright (C) 2010 Isotrol, SA. http://www.isotrol.com * * Port@l is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Port@l is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Port@l. If not, see <http://www.gnu.org/licenses/>. */ package com.isotrol.impe3.pms.core.obj; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Maps.filterKeys; import static com.isotrol.impe3.pms.core.obj.MessageMappers.transformSE; import static com.isotrol.impe3.pms.core.obj.ObjectFunctions.NAME2DTO; import static java.util.Collections.unmodifiableMap; import java.net.URI; import java.net.URISyntaxException; import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.UUID; import com.google.common.base.Function; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Ordering; import com.google.common.collect.Sets; import com.isotrol.impe3.api.Device; import com.isotrol.impe3.api.DeviceCapabilitiesProvider; import com.isotrol.impe3.api.DeviceInPortal; import com.isotrol.impe3.api.DeviceRouter; import com.isotrol.impe3.api.Devices; import com.isotrol.impe3.api.ETagMode; import com.isotrol.impe3.api.LocaleRouter; import com.isotrol.impe3.api.Name; import com.isotrol.impe3.api.PageResolver; import com.isotrol.impe3.api.Portal; import com.isotrol.impe3.core.BaseModel; import com.isotrol.impe3.core.PortalCacheModel; import com.isotrol.impe3.nr.api.NodeRepository; import com.isotrol.impe3.pbuf.portal.PortalProtos.BasesPB; import com.isotrol.impe3.pbuf.portal.PortalProtos.PortalConfigurationPB; import com.isotrol.impe3.pbuf.portal.PortalProtos.PortalNamePB; import com.isotrol.impe3.pbuf.portal.PortalProtos.PropertiesPB; import com.isotrol.impe3.pbuf.portal.PortalProtos.SetPB; import com.isotrol.impe3.pbuf.portal.PortalProtos.SetPB.SetTypePB; import com.isotrol.impe3.pbuf.portal.PortalProtos.SetsPB; import com.isotrol.impe3.pms.api.PMSException; import com.isotrol.impe3.pms.api.page.PageDeviceDTO; import com.isotrol.impe3.pms.api.portal.DeviceInPortalDTO; import com.isotrol.impe3.pms.api.portal.DeviceInPortalTreeDTO; import com.isotrol.impe3.pms.api.portal.PortalCacheDTO; import com.isotrol.impe3.pms.api.portal.PortalDevicesTemplateDTO; import com.isotrol.impe3.pms.api.portal.PortalInheritableFlag; import com.isotrol.impe3.pms.api.portal.PortalNameDTO; import com.isotrol.impe3.pms.api.portal.PortalSelDTO; import com.isotrol.impe3.pms.api.portal.PortalTemplateDTO; import com.isotrol.impe3.pms.api.portal.SetFilterDTO; import com.isotrol.impe3.pms.core.CacheKey; import com.isotrol.impe3.pms.core.PortalTxProvider; import com.isotrol.impe3.pms.core.support.AbstractSimpleValueLoader; import com.isotrol.impe3.pms.core.support.Functions; import com.isotrol.impe3.pms.core.support.Mappers; import com.isotrol.impe3.pms.core.support.MoreLocales; import com.isotrol.impe3.pms.model.DeviceEntity; import com.isotrol.impe3.pms.model.PortalCacheValue; import com.isotrol.impe3.pms.model.PortalConfigurationValue; import com.isotrol.impe3.pms.model.PortalDeviceValue; import com.isotrol.impe3.pms.model.PortalDfn; import com.isotrol.impe3.pms.model.SetFilterValue; import net.sf.derquinsej.i18n.Locales; /** * Category type domain object. * * @author Andres Rodriguez */ public final class PortalObject extends AbstractRoutableObject { static Function<PortalObject, PortalSelDTO> MAP2SEL = new Function<PortalObject, PortalSelDTO>() { public PortalSelDTO apply(PortalObject from) { return from.toSelDTO(); } }; private static final String NULL_NAME = "__NULL__"; private static Ordering<PageDeviceDTO> BY_NAME = Ordering.natural() .onResultOf(new Function<PageDeviceDTO, String>() { public String apply(PageDeviceDTO from) { return from.getDisplayName(); } }); public static Map<String, String> toNullName(Map<String, String> map) { return Maps.transformValues(map, new Function<String, String>() { public String apply(String from) { return from != null ? from : NULL_NAME; } }); } public static Map<String, String> fromNullName(Map<String, String> map) { return Maps.transformValues(map, new Function<String, String>() { public String apply(String from) { return NULL_NAME.equals(from) ? null : from; } }); } private static final BasesLoader BASES_LOADER = new BasesLoader(); private static final PropertiesLoader PROPERTIES_LOADER = new PropertiesLoader(); private static final PortalConfigurationLoader PORTAL_CONFIGURATION_LOADER = new PortalConfigurationLoader(); private static final SetFiltersLoader SETFILTERS_LOADER = new SetFiltersLoader(); private static final LocalesLoader LOCALES_LOADER = new LocalesLoader(); private static final DevicesLoader DEVICES_LOADER = new DevicesLoader(); /** Portal collection key. */ private final CacheKey portalsKey; /** Portal Edition Id. For offline objects is {@code null}. */ private final UUID editionId; /** Parent portal Id. */ private final UUID parentId; /** Routing domain id. */ private final UUID domainId; /** Portal name. */ private final Name name; /** Portal description. */ private final String description; /** Tag path segment. */ private final String tag; /** Router. */ private final Provider router; /** Locale resolver. */ private final Provider locale; /** Device resolver. */ private final Provider device; /** Device capabilities provider. */ private final Provider deviceCaps; /** Default node repository. */ private final Provider nodeRepository; /** Portal bases. */ private final Supplier<ImmutableMap<String, String>> bases; /** Portal properties. */ private final Supplier<ImmutableMap<String, String>> properties; /** Portal configuration. */ private final Supplier<ImmutableMap<String, PortalConfigurationValue>> portalConfiguration; /** Include uncategorized. */ private final PortalInheritableFlag uncategorized; /** Only due nodes. */ private final PortalInheritableFlag due; /** Default locale. */ private final Locale defaultLocale; /** Available locales. A hash map is used because null values are allowed. */ private final Supplier<Map<String, String>> locales; /** Set filters. */ private final Supplier<ImmutableMap<String, SetFilterValue>> setFilters; /** Devices. */ private final Supplier<PortalDevices> devices; /** Cache information. */ private final PortalCacheValue cache; /** Portal IA. */ private volatile IA ia = null; /** Whether to use session-based CSRF. */ private final PortalInheritableFlag sessionCSRF; private static ImmutableMap<UUID, DiPObj> deviceMap(DeviceEntity entity) { return ImmutableBiMap.of(entity.getId(), new DiPObj(entity)); } /** * Constructor. * @param tx Portals tx provider. * @param portalsKey Portals collection key. * @param editionId Edition id. * @param dfn Definition. */ PortalObject(PortalTxProvider tx, CacheKey portalsKey, UUID editionId, PortalDfn dfn) { super(dfn); checkArgument((portalsKey == null) != (editionId == null), "Inconsistent portal object."); this.portalsKey = portalsKey; this.editionId = editionId; this.parentId = dfn.getParentId(); this.domainId = dfn.getRoutingDomain().getId(); this.name = Functions.value2name(dfn.getName()); this.description = dfn.getDescription(); this.tag = dfn.getTag(); this.router = Provider.of(dfn.getRouterConnector(), dfn.getRouterBean()); this.locale = Provider.of(dfn.getLocaleConnector(), dfn.getLocaleBean()); this.device = Provider.of(dfn.getDeviceConnector(), dfn.getDeviceBean()); this.deviceCaps = Provider.of(dfn.getDeviceCapsConnector(), dfn.getDeviceCapsBean()); this.nodeRepository = Provider.of(dfn.getNrConnector(), dfn.getNrBean()); this.bases = tx.getTxSupplier(PortalDfn.class, dfn.getId(), null, BASES_LOADER); this.properties = tx.getTxSupplier(PortalDfn.class, dfn.getId(), null, PROPERTIES_LOADER); // ((PortalConfigurationValue)tx.getTxSupplier(PortalDfn.class, dfn.getParent().getCurrentId(), null, PORTAL_CONFIGURATION_LOADER).get().values().toArray()[0]).getPortalConfiguration().getValues().values() this.portalConfiguration = tx.getTxSupplier(PortalDfn.class, dfn.getId(), null, PORTAL_CONFIGURATION_LOADER); this.uncategorized = PortalInheritableFlag.fromBoolean(dfn.getUncategorized()); this.due = PortalInheritableFlag.fromBoolean(dfn.getDue()); this.defaultLocale = MoreLocales.fromString(dfn.getDefaultLocale(), MoreLocales.FALLBACK); this.locales = tx.getTxSupplier(PortalDfn.class, dfn.getId(), null, LOCALES_LOADER); this.setFilters = tx.getTxSupplier(PortalDfn.class, dfn.getId(), null, SETFILTERS_LOADER); this.sessionCSRF = PortalInheritableFlag.fromBoolean(dfn.getSessionCSRF()); // Devices this.devices = tx.getTxSupplier(PortalDfn.class, dfn.getId(), null, DEVICES_LOADER); // Cache PortalCacheValue cacheValue = dfn.getCache(); if (cacheValue == null) { this.cache = new PortalCacheValue(false, false, false, null, null, ETagMode.OFF); } else { this.cache = cacheValue; } } IA getIA(ContextGlobal ctx) { if (ia == null) { ia = ctx.getIA(); } return ia; } public boolean isOffline() { return portalsKey != null; } public CacheKey getPortalsKey() { return portalsKey; } public UUID getEditionId() { return editionId; } public UUID getParentId() { return parentId; } public UUID getDeviceId() { return devices.get().deviceId; } public UUID getDomainId() { return domainId; } public Name getName() { return name; } ImmutableMap<String, String> getBases() { return bases.get(); } ImmutableMap<String, String> getProperties() { return properties.get(); } /** * @return the portalConfiguration */ public ImmutableMap<String, PortalConfigurationValue> getPortalConfiguration() { return portalConfiguration.get(); } public boolean hasPortalConfiguration(String beanName) { return (portalConfiguration != null && getPortalConfiguration() != null && getPortalConfiguration().containsKey(beanName)); } public ImmutableMap<String, SetFilterValue> getSetFilters() { return setFilters.get(); } boolean isInheritedDevices() { return devices.get().inheritedDevices; } boolean isInheritedCache() { return cache.isInherited(); } public Portal start(BaseModel model, PortalsObject portals) { final Map<String, URI> ubases = Maps.newHashMap(); for (Entry<String, String> b : getActiveBases(portals).entrySet()) { try { ubases.put(b.getKey(), new URI(b.getValue())); } catch (URISyntaxException e) { // TODO } } final Devices devicesModel = model.getDevices(); final Function<DiPObj, DeviceInPortal> u2d = new Function<DiPObj, DeviceInPortal>() { public DeviceInPortal apply(DiPObj from) { final Device d = devicesModel.get(from.getDeviceId()); return DeviceInPortal.of(d, from.getName(), from.getUse()); } }; final Device defaultDevice = devicesModel.get(devices.get().deviceId); Set<DeviceInPortal> dm = ImmutableSet.copyOf(Iterables.transform(devices.get().devices.values(), u2d)); Portal.Builder b = Portal.builder().setId(getId()).setMode(model.getMode()).setDevice(defaultDevice) .setName(name.getDisplayName()).setContentTypes(model.getContentTypes()) .setCategories(model.getCategories()).setBases(ubases).setProperties(getActiveProperties(portals)) .setUncategorized(isUncategorized(portals)).setDue(isDue(portals)) .setSetFilters(Maps.transformValues(getSetFilters(), SetFilterValue.TYPE)).setDevices(dm) .setSessionCSRF(isSessionCSRF(portals)); // Locales if (defaultLocale != null) { Set<Locale> locs = Sets.newHashSet(defaultLocale); for (String sl : locales.get().keySet()) { locs.add(Locales.fromString(sl)); } b.setDefaultLocale(defaultLocale).setLocales(locs); } // Done return b.get(); } public PortalCacheModel getCacheModel(PortalsObject portals) { if (isInheritedCache() && parentId != null) { return portals.get(parentId).getCacheModel(portals); } if (cache.isActive()) { return PortalCacheModel.on(cache.isPublicCache(), cache.getModification(), cache.getModification(), cache.getETagMode()); } return PortalCacheModel.off(); } /** * Returns whether a connector is used by a provider of this portal. * @param provider Provider to check. * @param id Connector id. * @return True if the connector is used by the provider. */ private boolean isConnectorUsed(Provider p, UUID id) { return p != null && p.getConnectorId().equals(id); } /** * Returns whether a connector is used by this portal. * @param id Connector id. * @return True if the connector is used by this portal. */ boolean isConnectorUsed(UUID id) { return isConnectorUsed(router, id) || isConnectorUsed(locale, id) || isConnectorUsed(device, id) || isConnectorUsed(deviceCaps, id) || isConnectorUsed(nodeRepository, id); } /** * Transforms the object to a selection DTO. * @return The selection DTO. */ public PortalSelDTO toSelDTO() { final PortalSelDTO dto = new PortalSelDTO(); dto.setId(getStringId()); dto.setState(getState()); dto.setName(name.getDisplayName()); dto.setDescription(description); return dto; } public boolean isUncategorized(PortalsObject portals) { final PortalObject parent = portals.getParent(getId()); if (uncategorized != PortalInheritableFlag.INHERIT || parent == null) { return uncategorized.toBoolean(true); } return parent.isUncategorized(portals); } public boolean isDue(PortalsObject portals) { final PortalObject parent = portals.getParent(getId()); if (due != PortalInheritableFlag.INHERIT || parent == null) { return due.toBoolean(true); } return parent.isDue(portals); } private boolean isSessionCSRF(PortalsObject portals) { final PortalObject parent = portals.getParent(getId()); if (sessionCSRF != PortalInheritableFlag.INHERIT || parent == null) { return sessionCSRF.toBoolean(false); } return parent.isSessionCSRF(portals); } final Map<String, String> getActiveBases(PortalsObject portals) { if (parentId == null) { return getBases(); } final PortalObject parent = portals.get(parentId); Map<String, String> map = Maps.newHashMap(parent.getActiveBases(portals)); map.putAll(getBases()); return ImmutableMap.copyOf(map); } final Map<String, String> getActiveProperties(PortalsObject portals) { if (parentId == null) { return getProperties(); } final PortalObject parent = portals.get(parentId); Map<String, String> map = Maps.newHashMap(parent.getActiveProperties(portals)); map.putAll(getProperties()); return ImmutableMap.copyOf(map); } /** * Transforms the object to a PortalNameDTO. * * @param logger Logger. * @param portals Portals. * @param cnns Connectors. * @param locale Locale. * @return The template DTO. */ PortalNameDTO toNameDTO() { final PortalNameDTO dto = new PortalNameDTO(); dto.setId(getStringId()); dto.setName(NAME2DTO.apply(name)); dto.setDescription(description); dto.setDefaultLocale(defaultLocale.toString()); dto.setLocales(Maps.newHashMap(locales.get())); return dto; } List<PageDeviceDTO> getPageDeviceDTOs(ContextGlobal ctx) throws PMSException { if (isInheritedDevices() && parentId != null) { return ctx.getPortals().load(parentId).getPageDeviceDTOs(ctx); } final DevicesObject devicesObject = ctx.getDevices(); final Map<UUID, DiPObj> devMap = devices.get().devices; final UUID deviceId = devices.get().deviceId; List<PageDeviceDTO> list = Lists.newArrayListWithCapacity(devMap.size()); for (DiPObj dip : devMap.values()) { PageDeviceDTO dto = new PageDeviceDTO(); UUID did = dip.getDeviceId(); dto.setDevice(devicesObject.load(did).toSelDTO()); dto.setName(dip.getName()); dto.setDefaultDevice(deviceId.equals(did)); list.add(dto); } Collections.sort(list, BY_NAME); return list; } PortalDevicesTemplateDTO getPortalDevicesTemplateDTO(ContextGlobal ctx) throws PMSException { return getPortalDevicesTemplateDTO(ctx, this); } private PortalDevicesTemplateDTO getPortalDevicesTemplateDTO(ContextGlobal ctx, PortalObject portal) throws PMSException { final boolean child = parentId != null; if (isInheritedDevices() && child) { return ctx.getPortals().load(parentId).getPortalDevicesTemplateDTO(ctx, portal, true, true); } return getPortalDevicesTemplateDTO(ctx, portal, child, isInheritedDevices()); } private PortalDevicesTemplateDTO getPortalDevicesTemplateDTO(ContextGlobal ctx, PortalObject portal, boolean child, boolean inherited) throws PMSException { PortalDevicesTemplateDTO dto = new PortalDevicesTemplateDTO(); dto.setId(portal.getStringId()); dto.setChild(child); dto.setInherited(inherited); dto.setDevices(getDeviceTree(ctx.getDevices())); return dto; } PortalCacheDTO getPortalCacheDTO(ContextGlobal ctx) throws PMSException { return getPortalCacheDTO(ctx, this, false); } private PortalCacheDTO getPortalCacheDTO(ContextGlobal ctx, PortalObject portal, boolean inherited) throws PMSException { final boolean child = parentId != null && cache.isInherited(); if (child) { return ctx.getPortals().load(parentId).getPortalCacheDTO(ctx, portal, true); } final PortalCacheDTO dto = new PortalCacheDTO(); dto.setId(portal.getStringId()); dto.setInherited(inherited); dto.setActive(cache.isActive()); dto.setPublicCache(cache.isPublicCache()); dto.setModification(cache.getModification()); dto.setExpiration(cache.getExpiration()); dto.setETagMode(cache.getETagMode()); return dto; } private List<DeviceInPortalTreeDTO> getDeviceTree(final DevicesObject devicesObject) throws PMSException { final PortalDevices devs = devices.get(); final Function<DeviceObject, DeviceInPortalTreeDTO> tree = new Function<DeviceObject, DeviceInPortalTreeDTO>() { public DeviceInPortalTreeDTO apply(DeviceObject from) { final UUID did = from.getId(); final DeviceInPortalDTO node = new DeviceInPortalDTO(); if (devs.devices.containsKey(did)) { node.setActive(true); final DiPObj dip = devs.devices.get(did); node.setName(dip.getName()); node.setUse(dip.getUse()); node.setDefaultDevice(devs.deviceId.equals(did)); } else { node.setActive(false); node.setName(null); node.setDefaultDevice(false); } node.setDevice(from.toSelDTO()); final DeviceInPortalTreeDTO dto = new DeviceInPortalTreeDTO(); dto.setNode(node); dto.setChildren(Mappers.list(devicesObject.getChildren(did), this)); return dto; } }; return Mappers.list(devicesObject.getFirstLevel(), tree); } PortalNamePB toNamePB() { PortalNamePB.Builder b = PortalNamePB.newBuilder().setName(MessageMappers.name().apply(name)); if (description != null) { b.setDescription(description); } if (defaultLocale != null) { b.setDefaultLocale(defaultLocale.toString()); } b.addAllLocales(transformSE(toNullName(locales.get()))); return b.build(); } BasesPB exportBases() { return BasesPB.newBuilder().addAllBases(transformSE(getBases())).build(); } PropertiesPB exportProperties() { return PropertiesPB.newBuilder().addAllProperties(transformSE(getProperties())).build(); } SetsPB exportSets() { return SetsPB.newBuilder().addAllSets(transform(getSetFilters().entrySet(), Set2PB.INSTANCE)).build(); } /** * Transforms the object to a template DTO. * * @param ctx Global context. * @return The template DTO. */ PortalTemplateDTO toDTO(ContextGlobal ctx) { final PortalTemplateDTO dto = new PortalTemplateDTO(); final ConnectorsObject cnns = ctx.getConnectors(); final Locale locale = ctx.getLocale(); final RoutingDomainsObject rds = ctx.getDomains(); dto.setId(getStringId()); dto.setState(getState()); dto.setRoutable(isRoutable()); dto.setTag(tag); dto.setRouter(cnns.getProvidedTemplate(PageResolver.class, this.router, locale)); dto.setLocale(cnns.getProvidedTemplate(LocaleRouter.class, this.locale, locale)); dto.setDevice(cnns.getProvidedTemplate(DeviceRouter.class, this.device, locale)); dto.setDeviceCaps(cnns.getProvidedTemplate(DeviceCapabilitiesProvider.class, this.deviceCaps, locale)); dto.setNodeRepository(cnns.getProvidedTemplate(NodeRepository.class, this.nodeRepository, locale)); dto.setDefaultLocale(defaultLocale.toString()); dto.setLocales(Maps.newHashMap(locales.get())); dto.setUncategorized(uncategorized); dto.setDue(due); dto.setSessionCSRF(sessionCSRF); dto.setDomain(rds.get(domainId).toSel()); dto.setAvailableDomains(rds.map2sel(true)); return dto; } /** * Transforms the object to a configuration PB. * * @param ctx Global context. * @return The configuration PB. */ PortalConfigurationPB toConfigurationPB(ContextGlobal ctx) { PortalConfigurationPB.Builder b = PortalConfigurationPB.newBuilder(); b.setRoutable(isRoutable()); if (domainId != null) { b.setDomain(ctx.getDomains().get(domainId).getName()); } if (tag != null) { b.setTag(tag); } return null; // TODO } List<SetFilterDTO> getSetFilterDTOs() { ImmutableMap<String, SetFilterValue> filters = setFilters.get(); final List<SetFilterDTO> list = Lists.newArrayListWithCapacity(filters.size()); if (filters.isEmpty()) { return list; } for (String set : Ordering.natural().sortedCopy(filters.keySet())) { SetFilterValue v = filters.get(set); SetFilterDTO dto = new SetFilterDTO(); dto.setName(set); dto.setType(v.getType()); dto.setDescription(v.getDescription()); list.add(dto); } return list; } private enum Set2PB implements Function<Entry<String, SetFilterValue>, SetPB> { INSTANCE; public SetPB apply(Entry<String, SetFilterValue> from) { final SetPB.Builder b = SetPB.newBuilder().setName(from.getKey()); final SetFilterValue v = from.getValue(); switch (v.getType()) { case REQUIRED: b.setType(SetTypePB.REQUIRED); break; case OPTIONAL: b.setType(SetTypePB.OPTIONAL); break; case FORBIDDEN: b.setType(SetTypePB.FORBIDDEN); break; } if (v.getDescription() != null) { b.setDescription(v.getDescription()); } return b.build(); } } /** Bases loader. */ private static final class BasesLoader extends AbstractSimpleValueLoader<PortalDfn, ImmutableMap<String, String>> { BasesLoader() { super("Portal Bases"); } @Override protected ImmutableMap<String, String> load(PortalDfn dfn) { return ImmutableMap.copyOf(dfn.getBases()); } } /** Properties loader. */ private static final class PropertiesLoader extends AbstractSimpleValueLoader<PortalDfn, ImmutableMap<String, String>> { PropertiesLoader() { super("Portal Properties"); } @Override protected ImmutableMap<String, String> load(PortalDfn dfn) { return ImmutableMap.copyOf(dfn.getProperties()); } } /** Portal configurations loader. */ private static final class PortalConfigurationLoader extends AbstractSimpleValueLoader<PortalDfn, ImmutableMap<String, PortalConfigurationValue>> { PortalConfigurationLoader() { super("Portal Properties"); } @Override protected ImmutableMap<String, PortalConfigurationValue> load(PortalDfn dfn) { return ImmutableMap.copyOf(dfn.getPortalConfiguration()); } } /** Set Filters loader. */ private static final class SetFiltersLoader extends AbstractSimpleValueLoader<PortalDfn, ImmutableMap<String, SetFilterValue>> { SetFiltersLoader() { super("Portal Set Filters"); } @Override protected ImmutableMap<String, SetFilterValue> load(PortalDfn dfn) { return ImmutableMap.copyOf(dfn.getSetFilters()); } } /** Locales loader. */ private static final class LocalesLoader extends AbstractSimpleValueLoader<PortalDfn, Map<String, String>> { LocalesLoader() { super("Portal Locales"); } @Override protected Map<String, String> load(PortalDfn dfn) { Map<String, String> locs = Maps.newHashMap(); for (String loc : Iterables.filter(dfn.getLocales(), MoreLocales.VALID)) { locs.put(loc, null); } locs.putAll(filterKeys(dfn.getL7DNames(), MoreLocales.VALID)); return unmodifiableMap(locs); } } /** Portal devices. */ private static final class PortalDevices { /** Default device id. */ private final UUID deviceId; /** Devices. */ private final ImmutableMap<UUID, DiPObj> devices; /** Use parent portal devices. */ private final boolean inheritedDevices; /** Inherited. */ PortalDevices(DeviceEntity defaultDevice) { this.inheritedDevices = true; this.deviceId = defaultDevice.getId(); this.devices = deviceMap(defaultDevice); } /** Not inherited. */ PortalDevices(DeviceEntity defaultDevice, Map<DeviceEntity, PortalDeviceValue> devices) { this.inheritedDevices = false; UUID defaultDeviceId = null; final int n = devices.size(); final Map<UUID, DiPObj> deviceMap = Maps.newHashMapWithExpectedSize(n); final Set<String> names = Sets.newHashSetWithExpectedSize(n); for (Entry<DeviceEntity, PortalDeviceValue> e : devices.entrySet()) { final DiPObj dip = new DiPObj(e); if (!names.add(dip.getName())) { defaultDeviceId = null; break; } UUID did = dip.getDeviceId(); if (e.getValue().isDefaultDevice()) { if (defaultDeviceId != null) { defaultDeviceId = null; break; } defaultDeviceId = did; } deviceMap.put(did, dip); } if (defaultDeviceId != null) { this.deviceId = defaultDeviceId; this.devices = ImmutableBiMap.copyOf(deviceMap); } else { this.deviceId = defaultDevice.getId(); this.devices = deviceMap(defaultDevice); } } } /** Portal devices loader. */ private static final class DevicesLoader extends AbstractSimpleValueLoader<PortalDfn, PortalDevices> { DevicesLoader() { super("Portal Devices"); } @Override protected PortalDevices load(PortalDfn dfn) { final DeviceEntity defaultDevice = dfn.getEntity().getDefaultDevice(); if (dfn.isInheritedDevices()) { return new PortalDevices(defaultDevice); } else { return new PortalDevices(defaultDevice, dfn.getDevices()); } } } }