📄 sourcespage.java
字号:
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.wicket.examples.source;import java.io.BufferedReader;import java.io.File;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.net.JarURLConnection;import java.net.URI;import java.net.URISyntaxException;import java.net.URL;import java.net.URLConnection;import java.util.ArrayList;import java.util.Collections;import java.util.Enumeration;import java.util.List;import java.util.jar.JarEntry;import java.util.jar.JarFile;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.apache.wicket.Component;import org.apache.wicket.WicketRuntimeException;import org.apache.wicket.ajax.AjaxRequestTarget;import org.apache.wicket.ajax.markup.html.AjaxFallbackLink;import org.apache.wicket.markup.html.WebMarkupContainer;import org.apache.wicket.markup.html.WebPage;import org.apache.wicket.markup.html.basic.Label;import org.apache.wicket.markup.html.link.PopupCloseLink;import org.apache.wicket.markup.html.list.ListItem;import org.apache.wicket.markup.html.list.ListView;import org.apache.wicket.model.AbstractReadOnlyModel;import org.apache.wicket.model.IDetachable;import org.apache.wicket.model.PropertyModel;import org.apache.wicket.util.io.IOUtils;import org.apache.wicket.util.lang.PackageName;import org.apache.wicket.util.string.AppendingStringBuffer;import org.apache.wicket.util.string.Strings;import com.uwyn.jhighlight.renderer.Renderer;import com.uwyn.jhighlight.renderer.XhtmlRendererFactory;/** * Displays the resources in a packages directory in a browsable format. * * @author Martijn Dashorst */public class SourcesPage extends WebPage{ private static final Log log = LogFactory.getLog(SourcesPage.class); /** * Model for retrieving the source code from the classpath of a packaged resource. */ public class SourceModel extends AbstractReadOnlyModel { /** * Constructor. */ public SourceModel() { } /** * Returns the contents of the file loaded from the classpath. * * @return the contents of the file identified by name */ public Object getObject() { // name contains the name of the selected file if (Strings.isEmpty(name)) { return ""; } BufferedReader br = null; try { StringBuffer sb = new StringBuffer(); InputStream resourceAsStream = page.getResourceAsStream(name); if (resourceAsStream == null) { return "Unable to read the source for " + name; } br = new BufferedReader(new InputStreamReader(resourceAsStream)); while (br.ready()) { sb.append(br.readLine()); sb.append("\n"); } int lastDot = name.lastIndexOf('.'); if (lastDot != -1) { String type = name.substring(lastDot + 1); Renderer renderer = XhtmlRendererFactory.getRenderer(type); if (renderer != null) { return renderer.highlight(name, sb.toString(), "UTF-8", true); } } return Strings.escapeMarkup(sb.toString(), false, true).toString().replaceAll("\n", "<br />"); } catch (IOException e) { log.error("Unable to read resource stream for: " + name + "; Page=" + page.toString(), e); return ""; } finally { IOUtils.closeQuietly(br); } } } /** * Model for retrieving the contents of a package directory from the class path. */ public class PackagedResourcesModel extends AbstractReadOnlyModel implements IDetachable { private final List resources = new ArrayList(); /** * Constructor. */ public PackagedResourcesModel() { } /** * Clears the list to save space. */ protected void onDetach() { resources.clear(); } /** * Returns the list of resources found in the package of the page. * * @return the list of resources found in the package of the page. */ public Object getObject() { if (resources.isEmpty()) { get(page);// PackageName name = PackageName.forClass(page);// ClassLoader loader = page.getClassLoader();// String path = Strings.replaceAll(name.getName(), ".", "/").toString();// try// {// // gives the urls for each place where the package// // path could be found. There could be multiple// // jar files containing the same package, so each// // jar file has its own url.//// Enumeration urls = loader.getResources(path);// while (urls.hasMoreElements())// {// URL url = (URL)urls.nextElement();//// // the url points to the directory structure// // embedded in the classpath.//// getPackageContents(url);// }// }// catch (IOException e)// {// log.error("Unable to read resource for: " + path, e);// } } return resources; } /** * Retrieves the package contents for the given URL. * * @param packageListing * the url to list. */ private void getPackageContents(URL packageListing) { BufferedReader br = null; try { InputStream openStream = packageListing.openStream(); if (openStream == null) { return; } br = new BufferedReader(new InputStreamReader(openStream)); while (br.ready()) { String listing = br.readLine(); String extension = Strings.afterLast(listing, '.'); if (!listing.endsWith("class")) { resources.add(listing); } } } catch (IOException e) { log.error("Unable to get package content: " + packageListing.toString(), e); } finally { IOUtils.closeQuietly(br); } } private final void addResources(final Class scope, final AppendingStringBuffer relativePath, final File dir) { File[] files = dir.listFiles(); for (int i = 0; i < files.length; i++) { File file = files[i]; if (file.isDirectory()) { addResources(scope, new AppendingStringBuffer(relativePath).append( file.getName()).append('/'), file); } else { String name = file.getName(); String extension = Strings.afterLast(name, '.'); if (!name.endsWith("class")) { resources.add(relativePath + name); } } } } private void get(Class scope) { String packageRef = Strings.replaceAll(PackageName.forClass(scope).getName(), ".", "/") .toString(); ClassLoader loader = scope.getClassLoader(); try { // loop through the resources of the package Enumeration packageResources = loader.getResources(packageRef); while (packageResources.hasMoreElements()) { URL resource = (URL)packageResources.nextElement(); URLConnection connection = resource.openConnection(); if (connection instanceof JarURLConnection) { JarFile jf = ((JarURLConnection)connection).getJarFile(); scanJarFile(scope, packageRef, jf); } else { String absolutePath = scope.getResource("").toExternalForm(); File basedir; URI uri; try { uri = new URI(absolutePath); } catch (URISyntaxException e) { throw new RuntimeException(e); } try { basedir = new File(uri); } catch (IllegalArgumentException e) { log.debug("Can't construct the uri as a file: " + absolutePath); // if this is throwen then the path is not really a // file. but could be a zip. String jarZipPart = uri.getSchemeSpecificPart(); // lowercased for testing if jar/zip, but leave the // real filespec unchanged String lowerJarZipPart = jarZipPart.toLowerCase(); int index = lowerJarZipPart.indexOf(".zip"); if (index == -1) index = lowerJarZipPart.indexOf(".jar"); if (index == -1) throw e; String filename = jarZipPart.substring(0, index + 4); // 4 = // len // of // ".jar" // or // ".zip" log .debug("trying the filename: " + filename + " to load as a zip/jar."); JarFile jarFile = new JarFile(filename, false); scanJarFile(scope, packageRef, jarFile); return; } if (!basedir.isDirectory()) { throw new IllegalStateException( "unable to read resources from directory " + basedir); } addResources(scope, new AppendingStringBuffer(), basedir); } } } catch (IOException e) { throw new WicketRuntimeException(e); } Collections.sort(resources); return; } private void scanJarFile(Class scope, String packageRef, JarFile jf) { Enumeration enumeration = jf.entries(); while (enumeration.hasMoreElements()) { JarEntry je = (JarEntry)enumeration.nextElement(); String name = je.getName(); if (name.startsWith(packageRef)) { name = name.substring(packageRef.length() + 1); String extension = Strings.afterLast(name, '.'); if (!name.endsWith("class")) { resources.add(name); } } } } } /** * Displays the resources embedded in a package in a list. */ public class FilesBrowser extends WebMarkupContainer { /** * Constructor. * * @param id * the component identifier */ public FilesBrowser(String id) { super(id); ListView lv = new ListView("file", new PackagedResourcesModel()) { protected void populateItem(ListItem item) { AjaxFallbackLink link = new AjaxFallbackLink("link", item.getModel()) { public void onClick(AjaxRequestTarget target) { setName(getModelObjectAsString()); if (target != null) { target.addComponent(codePanel); target.addComponent(filename); } } }; link.add(new Label("name", item.getModelObjectAsString())); item.add(link); } }; add(lv); } } /** * Container for displaying the source of the selected page, resource or other element from the * package. */ public class CodePanel extends WebMarkupContainer { /** * Constructor. * * @param id * the component id */ public CodePanel(String id) { super(id); Label code = new Label("code", new SourceModel()); code.setEscapeModelStrings(false); code.setOutputMarkupId(true); add(code); } } /** * The selected name of the packaged resource to display. */ private String name; /** * The class of the page of which the sources need to be displayed. */ private Class page; /** * The panel for setting the ajax calls. */ private Component codePanel; private Label filename; /** * Sets the name. * * @param name * the name to set. */ public void setName(String name) { this.name = name; } /** * Gets the name. * * @return the name. */ public String getName() { return name; } /** * Default constructor, only used for test purposes. */ public SourcesPage() { this(SourcesPage.class); } /** * Constructor. * * @param page * the page where the sources need to be shown from. */ public SourcesPage(Class page) { this.page = page; filename = new Label("filename", new PropertyModel(this, "name")); filename.setOutputMarkupId(true); add(filename); codePanel = new CodePanel("codepanel").setOutputMarkupId(true); add(codePanel); add(new FilesBrowser("filespanel")); add(new PopupCloseLink("close")); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -