package hudson.plugins.pxe; import hudson.model.Hudson; import hudson.remoting.Channel; import hudson.remoting.RemoteInputStream; import hudson.remoting.VirtualChannel; import hudson.util.DescribableList; import org.apache.commons.io.IOUtils; import org.jvnet.hudson.tftpd.Data; import org.jvnet.hudson.tftpd.PathResolver; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.net.URL; /** * {@link PathResolver} implementation that projects the TFTP storage. * * <p> * The implementation is remoting safe. * * @author Kohsuke Kawaguchi */ final class PathResolverImpl implements PathResolver2, Serializable { public Data open(final String fileName) throws IOException { // dynamic resources DescribableList<BootConfiguration,BootConfigurationDescriptor> bootConfigurations = PXE.get().getBootConfigurations(); for(BootConfiguration config : bootConfigurations) { String id = config.getId()+'/'; if(fileName.startsWith(id)) { Data d = config.tftp(fileName.substring(id.length())); if(d!=null) return d; } } if(fileName.equals("pxelinux.cfg/default")) { // combine all pxelinux.cfg.fragment files into one and serve them StringBuilder buf = new StringBuilder(IOUtils.toString(getClass().getClassLoader().getResourceAsStream("tftp/"+fileName))); buf.append('\n'); // merge all fragments for (BootConfiguration conf : bootConfigurations) buf.append(conf.getPxeLinuxConfigFragment()).append('\n'); return Data.from(buf.toString()); } // static resources URL res = Hudson.getInstance().getPluginManager().uberClassLoader.getResource("tftp/"+fileName); if(res!=null) return Data.from(res); throw new IOException("No such file: "+fileName); } public int size(String path) throws IOException { return open(path).size(); } public InputStream read(String path) throws IOException { return new RemoteInputStream(open(path).read()); } /** * When sent to the remote JVM, send a proxy. */ private Object writeReplace() { return export(Channel.current()); } public PathResolver export(VirtualChannel channel) { return new RemotePathResolverProxy(channel.export(PathResolver2.class, this)); } /** * If {@link PathResolverImpl} is shipped to a remote JVM, this object is sent instead * to make everything remoting-safe. */ private static final class RemotePathResolverProxy implements PathResolver, Serializable { private final PathResolver2 proxy; private RemotePathResolverProxy(PathResolver2 proxy) { this.proxy = proxy; } public Data open(final String fileName) throws IOException { return new Data() { public InputStream read() throws IOException { return proxy.read(fileName); } public int size() throws IOException { return proxy.size(fileName); } }; } private static final long serialVersionUID = 1L; } }