Skip to content

Commit

Permalink
[JENKINS-21224] Defend against exceptions in listeners, for now just …
Browse files Browse the repository at this point in the history
…for ItemListener.

java.lang.RuntimeException: Unable to copy /…/jobs/…/config.xml
	at hudson.plugins.jobConfigHistory.FileHistoryDao.createNewHistoryEntryAndCopyConfig(FileHistoryDao.java:252)
	at hudson.plugins.jobConfigHistory.FileHistoryDao.createNewItem(FileHistoryDao.java:238)
	at hudson.plugins.jobConfigHistory.JobConfigHistoryJobListener.onCreated(JobConfigHistoryJobListener.java:31)
	at hudson.model.listeners.ItemListener.fireOnCreated(ItemListener.java:161)
	at jenkins.model.Jenkins.putItem(Jenkins.java:2483)
	at …
Caused by: java.io.FileNotFoundException: /…/jobs/…/config.xml (No such file or directory)
	at java.io.FileInputStream.open(Native Method)
	at java.io.FileInputStream.<init>(FileInputStream.java:120)
	at hudson.plugins.jobConfigHistory.FileHistoryDao.copyConfigFile(FileHistoryDao.java:178)
	at hudson.plugins.jobConfigHistory.FileHistoryDao.createNewHistoryEntryAndCopyConfig(FileHistoryDao.java:250)
	... 108 more
(cherry picked from commit 6825121)
  • Loading branch information
jglick authored and olivergondza committed Nov 8, 2014
1 parent 0efd811 commit b703134
Showing 1 changed file with 69 additions and 38 deletions.
107 changes: 69 additions & 38 deletions core/src/main/java/hudson/model/listeners/ItemListener.java
Expand Up @@ -23,13 +23,16 @@
*/
package hudson.model.listeners;

import com.google.common.base.Function;
import hudson.ExtensionPoint;
import hudson.ExtensionList;
import hudson.Extension;
import hudson.model.Item;
import hudson.model.ItemGroup;
import hudson.model.Items;
import hudson.security.ACL;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* Receives notifications about CRUD operations of {@link Item}.
Expand All @@ -38,6 +41,9 @@
* @author Kohsuke Kawaguchi
*/
public class ItemListener implements ExtensionPoint {

private static final Logger LOGGER = Logger.getLogger(ItemListener.class.getName());

/**
* Called after a new job is created and added to {@link jenkins.model.Jenkins},
* before the initial configuration page is provided.
Expand Down Expand Up @@ -151,45 +157,61 @@ public static ExtensionList<ItemListener> all() {
return ExtensionList.lookup(ItemListener.class);
}

public static void fireOnCopied(final Item src, final Item result) {
ACL.impersonate(ACL.SYSTEM, new Runnable() {
// TODO JENKINS-21224 generalize this to a method perhaps in ExtensionList and use consistently from all listeners
private static void forAll(final /* java.util.function.Consumer<ItemListener> */Function<ItemListener,Void> consumer, boolean asSystem) {
Runnable r = new Runnable() {
@Override public void run() {
for (ItemListener l : all()) {
l.onCopied(src, result);
try {
consumer.apply(l);
} catch (RuntimeException x) {
LOGGER.log(Level.WARNING, "failed to send event to listener of " + l.getClass(), x);
}
}
}
});
};
if (asSystem) {
ACL.impersonate(ACL.SYSTEM, r);
} else {
r.run();
}
}

public static void fireOnCopied(final Item src, final Item result) {
forAll(new Function<ItemListener,Void>() {
@Override public Void apply(ItemListener l) {
l.onCopied(src, result);
return null;
}
}, true);
}

public static void fireOnCreated(final Item item) {
ACL.impersonate(ACL.SYSTEM, new Runnable() {
@Override public void run() {
for (ItemListener l : all()) {
l.onCreated(item);
}
forAll(new Function<ItemListener,Void>() {
@Override public Void apply(ItemListener l) {
l.onCreated(item);
return null;
}
});
}, true);
}

public static void fireOnUpdated(final Item item) {
ACL.impersonate(ACL.SYSTEM, new Runnable() {
@Override public void run() {
for (ItemListener l : all()) {
l.onUpdated(item);
}
forAll(new Function<ItemListener,Void>() {
@Override public Void apply(ItemListener l) {
l.onUpdated(item);
return null;
}
});
}, true);
}

/** @since 1.548 */
public static void fireOnDeleted(final Item item) {
ACL.impersonate(ACL.SYSTEM, new Runnable() {
@Override public void run() {
for (ItemListener l : all()) {
l.onDeleted(item);
}
forAll(new Function<ItemListener,Void>() {
@Override public Void apply(ItemListener l) {
l.onDeleted(item);
return null;
}
});
}, true);
}

/**
Expand All @@ -205,34 +227,43 @@ public static void fireLocationChange(final Item rootItem, final String oldFullN
}
});
}
private static void doFireLocationChange(Item rootItem, String oldFullName) {
private static void doFireLocationChange(final Item rootItem, final String oldFullName) {
String prefix = rootItem.getParent().getFullName();
if (!prefix.isEmpty()) {
prefix += '/';
}
String newFullName = rootItem.getFullName();
final String newFullName = rootItem.getFullName();
assert newFullName.startsWith(prefix);
int prefixS = prefix.length();
if (oldFullName.startsWith(prefix) && oldFullName.indexOf('/', prefixS) == -1) {
String oldName = oldFullName.substring(prefixS);
String newName = rootItem.getName();
final String oldName = oldFullName.substring(prefixS);
final String newName = rootItem.getName();
assert newName.equals(newFullName.substring(prefixS));
for (ItemListener l : all()) {
l.onRenamed(rootItem, oldName, newName);
}
}
for (ItemListener l : all()) {
l.onLocationChanged(rootItem, oldFullName, newFullName);
forAll(new Function<ItemListener, Void>() {
@Override public Void apply(ItemListener l) {
l.onRenamed(rootItem, oldName, newName);
return null;
}
}, false);
}
forAll(new Function<ItemListener, Void>() {
@Override public Void apply(ItemListener l) {
l.onLocationChanged(rootItem, oldFullName, newFullName);
return null;
}
}, false);
if (rootItem instanceof ItemGroup) {
for (Item child : Items.getAllItems((ItemGroup) rootItem, Item.class)) {
String childNew = child.getFullName();
for (final Item child : Items.getAllItems((ItemGroup) rootItem, Item.class)) {
final String childNew = child.getFullName();
assert childNew.startsWith(newFullName);
assert childNew.charAt(newFullName.length()) == '/';
String childOld = oldFullName + childNew.substring(newFullName.length());
for (ItemListener l : all()) {
l.onLocationChanged(child, childOld, childNew);
}
final String childOld = oldFullName + childNew.substring(newFullName.length());
forAll(new Function<ItemListener, Void>() {
@Override public Void apply(ItemListener l) {
l.onLocationChanged(child, childOld, childNew);
return null;
}
}, false);
}
}
}
Expand Down

0 comments on commit b703134

Please sign in to comment.