/** * Takes a collection of StorageFiles and performs the replace functionality described in {@link * #replaceOriginal()}. However, all files that are part of the same {@link ShpFiles} are done * within a lock so all of the updates for all the Files of a Shapefile can be updated within a * single lock. * * @param storageFiles files to execute the replace functionality. * @throws IOException */ static void replaceOriginals(final StorageFile... storageFiles) throws IOException { SortedSet<StorageFile> files = new TreeSet<StorageFile>(Arrays.asList(storageFiles)); ShpFiles currentShpFiles = null; for (StorageFile storageFile : files) { if (currentShpFiles != storageFile.shpFiles) { // there's a new set of files so unlock old and lock new. currentShpFiles = storageFile.shpFiles; } final File storage = storageFile.getFile(); final URL url = storageFile.getSrcURLForWrite(); try { File dest = toFile(url); if (storage.equals(dest)) return; if (dest.exists()) { if (!dest.delete()) { LOGGER.severe( "Unable to delete the file: " + dest + " when attempting to replace with temporary copy."); } } if (storage.exists() && !storage.renameTo(dest)) { LOGGER.finer( "Unable to rename temporary file to the file: " + dest + " when attempting to replace with temporary copy"); copyFile(storage, url, dest); if (!storage.delete()) { storage.deleteOnExit(); } } } finally { if (storage.exists()) { storage.delete(); } } } }
@Override public void run() { /* * Do not retransmit a message if it has been acknowledged, * rejected, canceled or already been retransmitted for the maximum * number of times. */ try { int failedCount = exchange.getFailedTransmissionCount() + 1; exchange.setFailedTransmissionCount(failedCount); if (message.isAcknowledged()) { LOGGER.finest( "Timeout: message already acknowledged, cancel retransmission of " + message); return; } else if (message.isRejected()) { LOGGER.finest("Timeout: message already rejected, cancel retransmission of " + message); return; } else if (message.isCanceled()) { LOGGER.finest("Timeout: canceled (MID=" + message.getMID() + "), do not retransmit"); return; } else if (failedCount <= max_retransmit) { LOGGER.finer( "Timeout: retransmit message, failed: " + failedCount + ", message: " + message); // Trigger MessageObservers message.retransmitting(); // MessageObserver might have canceled if (!message.isCanceled()) retransmit(); } else { LOGGER.info( "Timeout: retransmission limit reached, exchange failed, message: " + message); exchange.setTimedOut(); message.setTimedOut(true); } } catch (Exception e) { e.printStackTrace(); } }
/** * Resolves all the groups that the user is in. * * <p>We now use <a * href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms680275(v=vs.85).aspx">tokenGroups</a> * attribute, which is a computed attribute that lists all the SIDs of the groups that the user is * directly/indirectly in. We then use that to retrieve all the groups in one query and resolve * their canonical names. * * @param userDN User's distinguished name. * @param context Used for making queries. */ private Set<GrantedAuthority> resolveGroups(String domainDN, String userDN, DirContext context) throws NamingException { LOGGER.finer("Looking up group of " + userDN); Attributes id = context.getAttributes(userDN, new String[] {"tokenGroups", "memberOf", "CN"}); Attribute tga = id.get("tokenGroups"); if (tga == null) { // see JENKINS-11644. still trying to figure out when this happens LOGGER.warning("Failed to retrieve tokenGroups for " + userDN); HashSet<GrantedAuthority> r = new HashSet<GrantedAuthority>(); r.add(new GrantedAuthorityImpl("unable-to-retrieve-tokenGroups")); return r; } // build up the query to retrieve all the groups StringBuilder query = new StringBuilder("(|"); List<byte[]> sids = new ArrayList<byte[]>(); NamingEnumeration<?> tokenGroups = tga.getAll(); while (tokenGroups.hasMore()) { byte[] gsid = (byte[]) tokenGroups.next(); query.append("(objectSid={" + sids.size() + "})"); sids.add(gsid); } tokenGroups.close(); query.append(")"); Set<GrantedAuthority> groups = new HashSet<GrantedAuthority>(); NamingEnumeration<SearchResult> renum = new LDAPSearchBuilder(context, domainDN) .subTreeScope() .returns("cn") .search(query.toString(), sids.toArray()); while (renum.hasMore()) { Attributes a = renum.next().getAttributes(); Attribute cn = a.get("cn"); if (LOGGER.isLoggable(Level.FINE)) LOGGER.fine(userDN + " is a member of " + cn); groups.add(new GrantedAuthorityImpl(cn.get().toString())); } renum.close(); { /* stage 2: use memberOf to find groups that aren't picked up by tokenGroups. This includes distribution groups */ LOGGER.fine("Stage 2: looking up via memberOf"); Stack<Attributes> q = new Stack<Attributes>(); q.push(id); while (!q.isEmpty()) { Attributes identity = q.pop(); LOGGER.finer("Looking up group of " + identity); Attribute memberOf = identity.get("memberOf"); if (memberOf == null) continue; for (int i = 0; i < memberOf.size(); i++) { try { Attributes group = context.getAttributes( new LdapName(memberOf.get(i).toString()), new String[] {"CN", "memberOf"}); Attribute cn = group.get("CN"); if (cn == null) { LOGGER.fine("Failed to obtain CN of " + memberOf.get(i)); continue; } if (LOGGER.isLoggable(Level.FINE)) LOGGER.fine(cn.get() + " is a member of " + memberOf.get(i)); if (groups.add(new GrantedAuthorityImpl(cn.get().toString()))) { q.add(group); // recursively look for groups that this group is a member of. } } catch (NameNotFoundException e) { LOGGER.fine("Failed to obtain CN of " + memberOf.get(i)); } } } } return groups; }
/** * Notify the commit to this repository. * * <p>Because this URL is not guarded, we can't really trust the data that's sent to us. But we * intentionally don't protect this URL to simplify <tt>post-commit</tt> script set up. */ public void doNotifyCommit(StaplerRequest req, StaplerResponse rsp) throws ServletException, IOException { requirePOST(); // compute the affected paths Set<String> affectedPath = new HashSet<String>(); String line; BufferedReader r = new BufferedReader(req.getReader()); try { while ((line = r.readLine()) != null) { if (LOGGER.isLoggable(FINER)) { LOGGER.finer("Reading line: " + line); } affectedPath.add(line.substring(4)); if (line.startsWith("svnlook changed --revision ")) { String msg = "Expecting the output from the svnlook command but instead you just sent me the svnlook invocation command line: " + line; LOGGER.warning(msg); throw new IllegalArgumentException(msg); } } } finally { IOUtils.closeQuietly(r); } if (LOGGER.isLoggable(FINE)) LOGGER.fine("Change reported to Subversion repository " + uuid + " on " + affectedPath); boolean scmFound = false, triggerFound = false, uuidFound = false, pathFound = false; // we can't reliably use req.getParameter() as it can try to parse the payload, which we've // already consumed above. // servlet container relies on Content-type to decide if it wants to parse the payload or not, // and at least // in case of Jetty, it doesn't check if the payload is QueryParameterMap query = new QueryParameterMap(req); String revParam = query.get("rev"); long rev = -1; if (revParam != null) { rev = Long.parseLong(revParam); } else { revParam = req.getHeader("X-Hudson-Subversion-Revision"); if (revParam != null) { rev = Long.parseLong(revParam); } } OUTER: for (AbstractProject<?, ?> p : Hudson.getInstance().getItems(AbstractProject.class)) { try { SCM scm = p.getScm(); if (scm instanceof SubversionSCM) scmFound = true; else continue; SCMTrigger trigger = p.getTrigger(SCMTrigger.class); if (trigger != null) triggerFound = true; else continue; SubversionSCM sscm = (SubversionSCM) scm; for (ModuleLocation loc : sscm.getLocations()) { if (loc.getUUID(p).equals(uuid)) uuidFound = true; else continue; String m = loc.getSVNURL().getPath(); String n = loc.getRepositoryRoot(p).getPath(); if (!m.startsWith(n)) continue; // repository root should be a subpath of the module path, but be defensive String remaining = m.substring(n.length()); if (remaining.startsWith("/")) remaining = remaining.substring(1); String remainingSlash = remaining + '/'; final RevisionParameterAction[] actions; if (rev != -1) { SvnInfo info[] = {new SvnInfo(loc.getURL(), rev)}; RevisionParameterAction action = new RevisionParameterAction(info); actions = new RevisionParameterAction[] {action}; } else { actions = new RevisionParameterAction[0]; } for (String path : affectedPath) { if (path.equals(remaining) /*for files*/ || path.startsWith(remainingSlash) /*for dirs*/) { // this project is possibly changed. poll now. // if any of the data we used was bogus, the trigger will not detect a change LOGGER.fine("Scheduling the immediate polling of " + p); trigger.run(actions); pathFound = true; continue OUTER; } } } } catch (SVNException e) { LOGGER.log(WARNING, "Failed to handle Subversion commit notification", e); } } if (!scmFound) LOGGER.warning("No subversion jobs found"); else if (!triggerFound) LOGGER.warning("No subversion jobs using SCM polling"); else if (!uuidFound) LOGGER.warning("No subversion jobs using repository: " + uuid); else if (!pathFound) LOGGER.fine("No jobs found matching the modified files"); rsp.setStatus(SC_OK); }