提交 b1a7477b 编写于 作者: K kohsuke

Improving convention-over-configuration for help files, and in particular I...

Improving convention-over-configuration for help files, and in particular I made it more seamless to switch between Jelly vs static HTML in help files.

I experimented with dynamically composed help page in slave ComputerLauncher, to accomodate for the extensible list. This pattern needs to be made into a tag.

Finally, picked up a new version of stapler to implement this.


git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@15354 71c3de6d-444a-0410-be80-ed276b4c234a
上级 7fdc2e84
......@@ -346,7 +346,7 @@ THE SOFTWARE.
<dependency>
<groupId>org.kohsuke.stapler</groupId>
<artifactId>stapler</artifactId>
<version>1.93</version>
<version>1.95</version>
</dependency>
<dependency>
<groupId>org.jvnet.localizer</groupId>
......
......@@ -33,13 +33,19 @@ import net.sf.json.JSONObject;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.MetaClass;
import org.kohsuke.stapler.WebApp;
import org.kohsuke.stapler.jelly.JellyClassTearOff;
import org.springframework.util.StringUtils;
import org.jvnet.tiger_types.Types;
import org.apache.commons.io.IOUtils;
import org.apache.commons.jelly.Script;
import org.apache.commons.jelly.JellyException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
import javax.servlet.ServletException;
import javax.servlet.RequestDispatcher;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
......@@ -50,6 +56,7 @@ import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Locale;
import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
......@@ -59,7 +66,6 @@ import java.lang.reflect.Type;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.beans.Introspector;
import java.net.URL;
/**
* Metadata about a configurable instance.
......@@ -355,9 +361,32 @@ public abstract class Descriptor<T extends Describable<T>> implements Saveable {
* null to indicate that there's no help.
*/
public String getHelpFile() {
InputStream in = getHelpStream();
return getHelpFile(null);
}
/**
* Returns the path to the help screen HTML for the given field.
*
* <p>
* The help files are assumed to be at "help/FIELDNAME.html" with possible
* locale variations.
*/
public String getHelpFile(String fieldName) {
if(fieldName==null) fieldName="";
else fieldName='/'+fieldName;
String page = "/descriptor/" + clazz.getName() + "/help"+fieldName;
try {
if(Stapler.getCurrentRequest().getView(clazz,"help"+fieldName+".jelly")!=null)
return page;
} catch (IOException e) {
throw new Error(e);
}
InputStream in = getHelpStream(fieldName);
IOUtils.closeQuietly(in);
if(in!=null) return "/descriptor/"+clazz.getName()+"/help";
if(in!=null) return page;
return null;
}
......@@ -475,8 +504,17 @@ public abstract class Descriptor<T extends Describable<T>> implements Saveable {
/**
* Serves <tt>help.html</tt> from the resource of {@link #clazz}.
*/
public void doHelp(StaplerResponse rsp) throws IOException {
InputStream in = getHelpStream();
public void doHelp(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
String path = req.getRestOfPath();
if(path.contains("..")) throw new ServletException("Illegal path: "+path);
RequestDispatcher rd = Stapler.getCurrentRequest().getView(clazz, "help"+path+".jelly");
if(rd!=null) {// Jelly-generated help page
rd.forward(req,rsp);
return;
}
InputStream in = getHelpStream(path);
if(in==null) {
rsp.sendError(SC_NOT_FOUND);
return;
......@@ -487,10 +525,10 @@ public abstract class Descriptor<T extends Describable<T>> implements Saveable {
in.close();
}
private InputStream getHelpStream() {
private InputStream getHelpStream(String suffix) {
Locale locale = Stapler.getCurrentRequest().getLocale();
String base = clazz.getName().replace('.', '/') + "/help";
String base = clazz.getName().replace('.', '/') + "/help"+suffix;
InputStream in;
in = clazz.getClassLoader().getResourceAsStream(base + '_' + locale.getLanguage() + '_' + locale.getCountry() + '_' + locale.getVariant() + ".html");
......@@ -516,10 +554,7 @@ public abstract class Descriptor<T extends Describable<T>> implements Saveable {
}
public static <T> List<T> toList( T... values ) {
final ArrayList<T> r = new ArrayList<T>();
for (T v : values)
r.add(v);
return r;
return new ArrayList<T>(Arrays.asList(values));
}
public static <T extends Describable<T>>
......@@ -625,4 +660,4 @@ public abstract class Descriptor<T extends Describable<T>> implements Saveable {
throw new AssertionError();
}
}
}
}
\ No newline at end of file
......@@ -27,21 +27,18 @@ import hudson.FilePath;
import hudson.Launcher;
import hudson.Launcher.RemoteLauncher;
import hudson.Util;
import hudson.slaves.ComputerLauncher;
import hudson.slaves.RetentionStrategy;
import hudson.slaves.CommandLauncher;
import hudson.slaves.JNLPLauncher;
import hudson.slaves.SlaveComputer;
import hudson.slaves.DumbSlave;
import hudson.slaves.*;
import hudson.model.Descriptor.FormException;
import hudson.remoting.Callable;
import hudson.remoting.VirtualChannel;
import hudson.tasks.DynamicLabeler;
import hudson.tasks.LabelFinder;
import hudson.util.ClockDifference;
import hudson.util.FormFieldValidator.NonNegativeInteger;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.WebMethod;
import org.apache.commons.io.IOUtils;
import javax.servlet.ServletException;
......@@ -391,6 +388,15 @@ public abstract class Slave extends Node implements Serializable {
return this;
}
public abstract SlaveDescriptor getDescriptor();
public static abstract class SlaveDescriptor extends NodeDescriptor {
public void doCheckNumExecutors() throws IOException, ServletException {
new NonNegativeInteger().process();
}
}
//
// backwrad compatibility
//
......
......@@ -25,12 +25,8 @@ package hudson.slaves;
import hudson.model.Descriptor.FormException;
import hudson.model.Slave;
import hudson.util.FormFieldValidator.NonNegativeInteger;
import org.kohsuke.stapler.DataBoundConstructor;
import javax.servlet.ServletException;
import java.io.IOException;
/**
* Default {@link Slave} implementation for computers that do not belong to a higher level structure,
* like grid or cloud.
......@@ -47,16 +43,12 @@ public final class DumbSlave extends Slave {
return DescriptorImpl.INSTANCE;
}
public static final class DescriptorImpl extends NodeDescriptor {
public static final class DescriptorImpl extends SlaveDescriptor {
public static final DescriptorImpl INSTANCE = new DescriptorImpl();
public String getDisplayName() {
return Messages.DumbSlave_displayName();
}
public void doCheckNumExecutors() throws IOException, ServletException {
new NonNegativeInteger().process();
}
}
static {
......
<!--
The MIT License
Copyright (c) 2004-2009, Sun Microsystems, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt">
<l:ajax>
<div>
Controls how Hudson starts this slave.
<dl>
<j:forEach var="d" items="${h.getComputerLauncherDescriptors()}">
<dt><b>${d.displayName}</b></dt>
<dd>
<st:include class="${d.clazz}" page="help.jelly" optional="true"/>
</dd>
</j:forEach>
</dl>
</div>
</l:ajax>
</j:jelly>
\ No newline at end of file
<!--
The MIT License
Copyright (c) 2004-2009, Sun Microsystems, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt">
Starts a slave by having Hudson execute a command from the master.
Use this when the master is capable of remotely executing a process
on a slave, such as through ssh/rsh.
</j:jelly>
\ No newline at end of file
......@@ -48,7 +48,7 @@ THE SOFTWARE.
<f:slave-mode name="mode" node="${it}" />
<f:dropdownList name="slave.launcher" title="${%Launch method}"
help="/help/system-config/master-slave/startMethod.html">
help="${descriptor.getHelpFile('launcher')}">
<j:forEach var="d" items="${h.getComputerLauncherDescriptors()}" varStatus="loop">
<f:dropdownListBlock value="${d.clazz.name}" name="${d.displayName}"
selected="${it.launcher.descriptor==d}"
......
<!--
The MIT License
Copyright (c) 2004-2009, Sun Microsystems, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt">
Starts a slave by launching an agent program through
<a href="http://en.wikipedia.org/wiki/Java_Web_Start">JNLP</a>.
The launch in this case is initiated by the slave,
although it is possible to start a launch without GUI, for example
as a Windows service.
</j:jelly>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册