/*
* Copyright (c) 2002-2012 Alibaba Group Holding Limited.
* All rights reserved.
*
* 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 com.alibaba.citrus.webx.handler.component;
import static com.alibaba.citrus.util.Assert.*;
import static com.alibaba.citrus.util.CollectionUtil.*;
import static com.alibaba.citrus.util.StringEscapeUtil.*;
import java.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.Map;
import com.alibaba.citrus.util.internal.webpagelite.PageComponent;
import com.alibaba.citrus.util.internal.webpagelite.PageComponentRegistry;
import com.alibaba.citrus.util.templatelite.Template;
import com.alibaba.citrus.webx.handler.RequestHandlerContext;
import com.alibaba.citrus.webx.handler.RequestHandlerMapping;
import com.alibaba.citrus.webx.handler.support.AbstractVisitor;
import org.springframework.beans.factory.annotation.Autowired;
/**
* 用来显示可用handler菜单的组件。
*
* @author Michael Zhou
*/
public class MenuComponent extends PageComponent {
@Autowired
private RequestHandlerMapping internalHandlers;
public MenuComponent(PageComponentRegistry registry, String componentPath) {
super(registry, componentPath);
}
public void visitTemplate(RequestHandlerContext context, String selection) {
getTemplate().accept(new MenuVisitor(context, createRootEntry(), selection));
}
private Entry createRootEntry() {
Entry root = new Entry();
for (String name : internalHandlers.getRequestHandlerNames()) {
Entry entry = root;
int index = name.indexOf('/');
for (; index >= 0; index = name.indexOf('/', index + 1)) {
String catName = name.substring(0, index + 1); // 例如:cat1/cat2/
entry = entry.getOrCreateSubEntry(catName);
}
entry.getOrCreateSubEntry(name); // 例如:cat1/cat2/item1
}
return root;
}
@SuppressWarnings("unused")
private class MenuVisitor extends AbstractVisitor {
private final String selection;
private final Entry rootEntry;
public MenuVisitor(RequestHandlerContext context, Entry rootEntry, String selection) {
super(context, MenuComponent.this);
this.selection = selection;
this.rootEntry = rootEntry;
}
public void visitEntry(Template homeTemplate, Template catTemplate, Template itemTemplate) {
homeTemplate.accept(this);
for (Entry subEntry : rootEntry.getSubEntries()) {
if (subEntry.isCategory()) {
catTemplate.accept(new CatEntryVisitor(context, subEntry));
} else {
itemTemplate.accept(new ItemEntryVisitor(context, subEntry));
}
}
}
public void visitInternalHomePage() {
out().print(context.getInternalResourceURL("/"));
}
public void visitOriginalHomePage() {
out().print(context.getInternalResourceURL("../") + "?home");
}
}
private abstract class AbstractEntryVisitor extends AbstractVisitor {
protected final Entry entry;
public AbstractEntryVisitor(RequestHandlerContext context, Entry entry) {
super(context, MenuComponent.this);
this.entry = entry;
}
}
@SuppressWarnings("unused")
private class CatEntryVisitor extends AbstractEntryVisitor {
public CatEntryVisitor(RequestHandlerContext context, Entry entry) {
super(context, entry);
}
public void visitCatName() {
out().print(entry.getName());
}
public void visitSubEntries(Template noSubEntriesTemplate, Template withSubEntriesTemplate) {
if (entry.getSubEntries().isEmpty()) {
noSubEntriesTemplate.accept(this);
} else {
withSubEntriesTemplate.accept(this);
}
}
public void visitSubEntriesRecursive(Template catTemplate, Template itemTemplate) {
for (Entry subEntry : entry.getSubEntries()) {
if (subEntry.isCategory()) {
catTemplate.accept(new CatEntryVisitor(context, subEntry));
} else {
itemTemplate.accept(new ItemEntryVisitor(context, subEntry));
}
}
}
}
@SuppressWarnings("unused")
private class ItemEntryVisitor extends AbstractEntryVisitor {
public ItemEntryVisitor(RequestHandlerContext context, Entry entry) {
super(context, entry);
}
public void visitItemUrl() {
out().print(context.getInternalResourceURL(entry.getPath()));
}
public void visitItemName() {
out().print(entry.getName());
}
}
@SuppressWarnings("unused")
private static class Entry {
private final String path;
private final String name;
private final boolean category;
private final boolean root;
private Map<String, Entry> subEntries;
/** 创建特殊的root entry。 */
private Entry() {
this.path = "";
this.name = "";
this.category = true;
this.root = true;
this.subEntries = createTreeMap();
}
public Entry(String path) {
this.path = path;
this.category = path.endsWith("/");
this.name = getName(path);
this.root = false;
this.subEntries = createTreeMap();
}
private String getName(String path) {
int fromIndex = this.category ? path.length() - 2 : path.length();
try {
return unescapeURL(
path.substring(path.lastIndexOf("/", fromIndex) + 1, path.length() - (this.category ? 1 : 0)),
"UTF-8");
} catch (UnsupportedEncodingException e) {
unreachableCode();
return null;
}
}
public String getPath() {
return path;
}
public String getName() {
return name;
}
public boolean isCategory() {
return category;
}
public boolean isRoot() {
return root;
}
public Entry getOrCreateSubEntry(String path) {
Entry subEntry = subEntries.get(path);
if (subEntry == null) {
subEntry = new Entry(path);
subEntries.put(path, subEntry);
}
return subEntry;
}
public Collection<Entry> getSubEntries() {
return subEntries.values();
}
@Override
public String toString() {
return root ? "/" : path;
}
}
}