/* * 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.springext.export; import java.io.IOException; import java.io.PrintWriter; import com.alibaba.citrus.springext.Schema; import com.alibaba.citrus.util.internal.webpagelite.RequestContext; import com.alibaba.citrus.util.internal.webpagelite.RequestProcessor; import com.alibaba.citrus.util.templatelite.FallbackTextWriter; import com.alibaba.citrus.util.templatelite.Template; import com.alibaba.citrus.util.templatelite.TextWriter; /** * 在WEB上调用<code>SchemaExporter</code>,可以把schema显示在WEB页面中。 * * <p> * 本类不依赖于servlet api。request和response创建适配器。 * </p> * * @author Michael Zhou */ public class SchemaExporterWEB extends SchemaExporter { private final Template listTemplate = new Template(getClass().getResource("list.htm")); private final RequestProcessor<RequestContext> processor = new RequestProcessor<RequestContext>() { @Override protected boolean resourceExists(String resourceName) { return getEntry(resourceName) != null; } @Override protected void renderPage(RequestContext request, String resourceName) throws IOException { Entry entry = getEntry(resourceName); if (entry.isDirectory()) { renderListPage(request, entry); // 渲染list页面 } else { renderContentPage(request, entry); // 渲染schema内容页面 } } }; private final MenuProvider menuProvider; public SchemaExporterWEB() { this(null); } public SchemaExporterWEB(MenuProvider menuProvider) { this.menuProvider = menuProvider; } public MenuProvider getMenuProvider() { return menuProvider; } public interface MenuProvider { /** 由子类在list页面中插入菜单。 */ void renderMenuHead(RequestContext request) throws Exception; /** 由子类在list页面中插入菜单。 */ void renderMenu(RequestContext request) throws Exception; } /** 处理请求。 */ public void processRequest(RequestContext request) throws IOException { processor.processRequest(request); } /** 渲染列表页面。 */ private void renderListPage(final RequestContext request, final Entry rootEntry) throws IOException { PrintWriter out = request.getWriter("text/html; charset=UTF-8"); listTemplate.accept(new ListPageVisitor(out, request, rootEntry, "text/html; charset=UTF-8")); out.flush(); } /** 渲染schema文件页面。 */ private void renderContentPage(RequestContext request, Entry entry) throws IOException { PrintWriter out = request.getWriter("text/xml; charset=UTF-8"); writeTo(out, entry, "UTF-8", request.getResourceURL("/")); out.flush(); } @SuppressWarnings("unused") private class AbstractEntryVisitor extends TextWriter<PrintWriter> { protected final RequestContext request; protected final String lastEntryPath; protected final Entry entry; public AbstractEntryVisitor(PrintWriter out, RequestContext request, Entry entry, String lastEntryPath) { super(out); this.request = request; this.entry = entry; this.lastEntryPath = lastEntryPath; } public void visitUrl(String relativeUrl) { out().print(request.getResourceURL(relativeUrl)); } public void visitEntryUrl() { out().append(request.getResourceURL(entry.getPath())); } public void visitEntryName() { out().append(entry.getName()); } public void visitEntryClass() { if (entry.isDirectory()) { out().append("directory"); } else { out().append("file"); } if (!entry.containsSchemaWithTargetNamespace()) { out().append(" no-target-namespace"); } } public void visitEntryId() { out().append(entry.getId()); } } @SuppressWarnings("unused") private class ListPageVisitor extends AbstractEntryVisitor { private String contentTypeAndCharset; public ListPageVisitor(PrintWriter out, RequestContext request, Entry firstEntry, String contentTypeAndCharset) { super(out, request, firstEntry, null); this.contentTypeAndCharset = contentTypeAndCharset; } public void visitEntry(Template dirTemplate, Template fileTemplate) { if (entry.isDirectory()) { dirTemplate.accept(new DirEntryVisitor(out(), request, entry, null)); } else { fileTemplate.accept(new FileEntryVisitor(out(), request, entry, null)); } } public void visitContentTypeAndCharset() { out().append(contentTypeAndCharset); } public void visitMenuHead() throws Exception { if (menuProvider != null) { menuProvider.renderMenuHead(request); } } public void visitMenu() throws Exception { if (menuProvider != null) { menuProvider.renderMenu(request); } } } @SuppressWarnings("unused") private class DirEntryVisitor extends AbstractEntryVisitor { public DirEntryVisitor(PrintWriter out, RequestContext request, Entry entry, String lastEntryPath) { super(out, request, entry, lastEntryPath); } public void visitEntryLink(Template link) { FallbackTextWriter<PrintWriter> v = new FallbackTextWriter<PrintWriter>(out()); int lastEntryPathLength = 0; if (lastEntryPath == null) { v.context().put("entryUrl", request.getResourceURL("/")); v.context().put("entryName", "all"); link.accept(v); } else { lastEntryPathLength = lastEntryPath.length(); } String path = entry.getPath(); for (int i = path.indexOf("/", lastEntryPathLength); i >= 0; i = path.indexOf("/", i + 1)) { Entry parentEntry = getEntry(path.substring(0, i + 1)); v.context().put("entryUrl", request.getResourceURL(parentEntry.getPath())); v.context().put("entryName", parentEntry.getName().replaceFirst("/$", "")); link.accept(v); } } public void visitSubEntries(Template subEntriesTemplate) { if (!entry.getSubEntries().isEmpty()) { subEntriesTemplate.accept(this); } } public void visitSubEntryRecursive(Template dirTemplate, Template fileTemplate) { for (Entry subEntry : entry.getSubEntries()) { Entry activeEntry = subEntry; while (activeEntry.isDirectory() && activeEntry.getSubEntries().size() == 1) { Entry theOnlySubEntry = activeEntry.getSubEntries().iterator().next(); if (theOnlySubEntry.isDirectory()) { activeEntry = theOnlySubEntry; } else { break; } } if (activeEntry.isDirectory()) { dirTemplate.accept(new DirEntryVisitor(out(), request, activeEntry, entry.getPath())); } else { fileTemplate.accept(new FileEntryVisitor(out(), request, activeEntry, entry.getPath())); } } } } @SuppressWarnings("unused") private class FileEntryVisitor extends AbstractEntryVisitor { private final Schema schema; private final String namespace; public FileEntryVisitor(PrintWriter out, RequestContext request, Entry entry, String lastEntryPath) { super(out, request, entry, lastEntryPath); this.schema = entry.getSchema(); this.namespace = schema != null ? schema.getTargetNamespace() : null; } public void visitCheckbox(Template chkbox) { if (namespace != null) { chkbox.accept(this); } } public void visitNamespace(Template ns, Template noNs) { if (namespace != null) { ns.accept(this); } else { noNs.accept(this); } } public void visitNsPrefix() { out().append(schema.getNamespacePrefix()); } public void visitNs() { out().append(namespace); } public void visitDescription(Template descTemplate) { if (schema != null && schema.getSourceDescription() != null) { descTemplate.accept(this); } } public void visitDesc() { out().append(schema.getSourceDescription()); } } }