/*
*
* * Copyright (c) 2016. David Sowerby
* *
* * 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 uk.q3c.krail.core.navigate.sitemap;
import com.google.inject.Inject;
import net.engio.mbassy.bus.common.PubSubSupport;
import net.engio.mbassy.listener.Handler;
import net.engio.mbassy.listener.Listener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uk.q3c.krail.core.eventbus.BusMessage;
import uk.q3c.krail.core.eventbus.SessionBusProvider;
import uk.q3c.krail.core.guice.vsscope.VaadinSessionScoped;
import uk.q3c.krail.core.i18n.CurrentLocale;
import uk.q3c.krail.core.i18n.LocaleChangeBusMessage;
import uk.q3c.krail.core.i18n.Translate;
import uk.q3c.krail.core.navigate.URIFragmentHandler;
import javax.annotation.Nonnull;
import java.text.Collator;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* The {@link MasterSitemap} provides the overall structure of the site, and is Singleton scoped. This class refines
* that by presenting only those pages that the user is authorised to see, and is therefore {@link
* VaadinSessionScoped}.
* It also maintains locale-aware labels and sort order, so that the navigation components are presented to the user in
* the language and sort order of their choice.
* <p>
* The standard page nodes are sometimes not in the user sitemap (for example, the login node is not there after
* login). Use the isxxxUri methods to test a uri for a match to a standard page
*
* @author David Sowerby
* @date 17 May 2014
*/
@VaadinSessionScoped
@Listener
public class DefaultUserSitemap extends DefaultSitemapBase<UserSitemapNode> implements UserSitemap {
private static Logger log = LoggerFactory.getLogger(DefaultUserSitemap.class);
private final Translate translate;
private final PubSubSupport<BusMessage> eventBus;
@Inject
public DefaultUserSitemap(Translate translate, URIFragmentHandler uriHandler, SessionBusProvider eventBusProvider) {
super(uriHandler);
this.translate = translate;
this.eventBus = eventBusProvider.get();
}
/**
* Iterates through contained nodes and resets the label and collation key properties to reflect a change in
* {@link CurrentLocale}. There is no need to reload all the nodes, no change of page authorisation is dealt with
* here}
*/
@Handler
public synchronized void localeChanged(@Nonnull LocaleChangeBusMessage busMessage) {
checkNotNull(busMessage);
log.debug("responding to locale change to {}", busMessage.getNewLocale());
List<UserSitemapNode> nodeList = getAllNodes();
Collator collator = translate.collator();
for (UserSitemapNode userNode : nodeList) {
String label = translate.from(userNode.getMasterNode()
.getLabelKey());
userNode.setLabel(label);
userNode.setCollationKey(collator.getCollationKey(userNode.getLabel()));
}
eventBus.publish(new UserSitemapLabelChangeMessage());
}
/**
* Returns the userNode which contains {@code masterNode}. Note that this method is not very efficient for larger
* instances, it has to scan the {@link UserSitemap} until it finds a match. Returns null if no match found (and
* will have scanned the entire {@link UserSitemap}
*
* @param masterNode
* @return
*/
@Override
public synchronized UserSitemapNode userNodeFor(@Nonnull SitemapNode masterNode) {
checkNotNull(masterNode);
for (UserSitemapNode candidate : getAllNodes()) {
if (candidate.getMasterNode() == masterNode) {
return candidate;
}
}
return null;
}
/**
* The {@link UserSitemap} never creates a node this way
*/
@Override
public UserSitemapNode createNode(String segment) {
return null;
}
@Override
public synchronized void setLoaded(boolean loaded) {
super.setLoaded(loaded);
buildUriMap();
if (loaded) {
eventBus.publish(new UserSitemapStructureChangeMessage());
}
}
@Override
public synchronized void buildUriMap() {
uriMap.clear();
for (UserSitemapNode node : forest.getAllNodes()) {
uriMap.put(uri(node), node);
}
}
@Override
public boolean hasNoVisibleChildren(@Nonnull UserSitemapNode sourceNode) {
checkNotNull(sourceNode);
List<UserSitemapNode> children = this.getChildren(sourceNode);
// if (children == null) { //FindBugs reports this unnecessary
// return true;
// }
for (UserSitemapNode child : children) {
if (child.getPositionIndex() >= 0) {
return false;
}
}
return true;
}
public Translate getTranslate() {
return translate;
}
}