| /* |
| * Copyright 2000-2012 JetBrains s.r.o. |
| * |
| * Licensed 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.jetbrains.idea.svn.status; |
| |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.util.Getter; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.util.containers.Convertor; |
| import com.intellij.util.containers.MultiMap; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| import org.jetbrains.idea.svn.SvnUtil; |
| import org.jetbrains.idea.svn.api.NodeKind; |
| import org.jetbrains.idea.svn.info.Info; |
| import org.jetbrains.idea.svn.lock.Lock; |
| import org.tmatesoft.svn.core.internal.util.SVNDate; |
| import org.tmatesoft.svn.core.wc.SVNRevision; |
| import org.xml.sax.Attributes; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.helpers.DefaultHandler; |
| |
| import java.io.File; |
| import java.util.*; |
| |
| /** |
| * Created with IntelliJ IDEA. |
| * User: Irina.Chernushina |
| * Date: 1/25/12 |
| * Time: 7:59 PM |
| */ |
| public class SvnStatusHandler extends DefaultHandler { |
| |
| private static final Logger LOG = Logger.getInstance(SvnStatusHandler.class); |
| |
| @Nullable |
| public static StatusType getStatus(@NotNull String code) { |
| StatusType result = StatusType.forStatusOperation(code); |
| |
| if (result == null) { |
| LOG.info("Unknown status type " + code); |
| } |
| |
| return result; |
| } |
| |
| private String myChangelistName; |
| private List<PortableStatus> myDefaultListStatuses; |
| private MultiMap<String, PortableStatus> myCurrentListChanges; |
| private PortableStatus myPending; |
| private boolean myInRemoteStatus; |
| private Lock.Builder myLockBuilder; |
| |
| private final List<ElementHandlerBase> myParseStack; |
| private final Map<String, Getter<ElementHandlerBase>> myElementsMap; |
| private final DataCallback myDataCallback; |
| private final File myBase; |
| private final StringBuilder mySb; |
| private boolean myAnythingReported; |
| |
| public SvnStatusHandler(final ExternalDataCallback dataCallback, File base, final Convertor<File, Info> infoGetter) { |
| myBase = base; |
| myParseStack = new ArrayList<ElementHandlerBase>(); |
| myParseStack.add(new Fake()); |
| |
| myElementsMap = new HashMap<String, Getter<ElementHandlerBase>>(); |
| fillElements(); |
| |
| if (dataCallback != null) { |
| myDataCallback = new DataCallback() { |
| @Override |
| public void startLock() { |
| myLockBuilder = new Lock.Builder(); |
| } |
| |
| @Override |
| public void endLock() { |
| if (myInRemoteStatus) { |
| myPending.setRemoteLock(myLockBuilder.build()); |
| } else { |
| myPending.setLocalLock(myLockBuilder.build()); |
| } |
| myLockBuilder = null; |
| } |
| |
| @Override |
| public void startRemoteStatus() { |
| myInRemoteStatus = true; |
| } |
| |
| @Override |
| public void endRemoteStatus() { |
| myInRemoteStatus = false; |
| } |
| |
| @Override |
| public void switchPath() { |
| myAnythingReported = true; |
| dataCallback.switchPath(); |
| newPending(infoGetter); |
| } |
| |
| @Override |
| public void switchChangeList(String newList) { |
| dataCallback.switchChangeList(newList); |
| } |
| }; |
| } else { |
| myDataCallback = new DataCallback() { |
| @Override |
| public void startLock() { |
| myLockBuilder = new Lock.Builder(); |
| } |
| |
| @Override |
| public void endLock() { |
| if (myInRemoteStatus) { |
| myPending.setRemoteLock(myLockBuilder.build()); |
| } else { |
| myPending.setLocalLock(myLockBuilder.build()); |
| } |
| myLockBuilder = null; |
| } |
| |
| @Override |
| public void startRemoteStatus() { |
| myInRemoteStatus = true; |
| } |
| |
| @Override |
| public void endRemoteStatus() { |
| myInRemoteStatus = false; |
| } |
| |
| @Override |
| public void switchPath() { |
| myAnythingReported = true; |
| if (myChangelistName == null) { |
| myDefaultListStatuses.add(myPending); |
| } else { |
| myCurrentListChanges.putValue(myChangelistName, myPending); |
| } |
| newPending(infoGetter); |
| } |
| |
| @Override |
| public void switchChangeList(String newList) { |
| myChangelistName = newList; |
| } |
| }; |
| } |
| newPending(infoGetter); |
| mySb = new StringBuilder(); |
| } |
| |
| public boolean isAnythingReported() { |
| return myAnythingReported; |
| } |
| |
| private void newPending(final Convertor<File, Info> infoGetter) { |
| final PortableStatus status = new PortableStatus(); |
| myPending = status; |
| status.setInfoGetter(new Getter<Info>() { |
| @Override |
| public Info get() { |
| return infoGetter.convert(status.getFile()); |
| } |
| }); |
| } |
| |
| public PortableStatus getPending() { |
| return myPending; |
| } |
| |
| public List<PortableStatus> getDefaultListStatuses() { |
| return myDefaultListStatuses; |
| } |
| |
| public MultiMap<String, PortableStatus> getCurrentListChanges() { |
| return myCurrentListChanges; |
| } |
| |
| private void fillElements() { |
| myElementsMap.put("repos-status", new Getter<ElementHandlerBase>() { |
| @Override |
| public ElementHandlerBase get() { |
| return new ReposStatus(); |
| } |
| }); |
| myElementsMap.put("lock", new Getter<ElementHandlerBase>() { |
| @Override |
| public ElementHandlerBase get() { |
| return new LockElement(); |
| } |
| }); |
| |
| myElementsMap.put("token", new Getter<ElementHandlerBase>() { |
| @Override |
| public ElementHandlerBase get() { |
| return new LockToken(); |
| } |
| }); |
| myElementsMap.put("owner", new Getter<ElementHandlerBase>() { |
| @Override |
| public ElementHandlerBase get() { |
| return new LockOwner(); |
| } |
| }); |
| myElementsMap.put("comment", new Getter<ElementHandlerBase>() { |
| @Override |
| public ElementHandlerBase get() { |
| return new LockComment(); |
| } |
| }); |
| myElementsMap.put("created", new Getter<ElementHandlerBase>() { |
| @Override |
| public ElementHandlerBase get() { |
| return new LockCreatedDate(); |
| } |
| }); |
| // -- |
| myElementsMap.put("status", new Getter<ElementHandlerBase>() { |
| @Override |
| public ElementHandlerBase get() { |
| return new Status(); |
| } |
| }); |
| myElementsMap.put("author", new Getter<ElementHandlerBase>() { |
| @Override |
| public ElementHandlerBase get() { |
| return new Author(); |
| } |
| }); |
| myElementsMap.put("changelist", new Getter<ElementHandlerBase>() { |
| @Override |
| public ElementHandlerBase get() { |
| return new Changelist(); |
| } |
| }); |
| myElementsMap.put("commit", new Getter<ElementHandlerBase>() { |
| @Override |
| public ElementHandlerBase get() { |
| return new Commit(); |
| } |
| }); |
| myElementsMap.put("date", new Getter<ElementHandlerBase>() { |
| @Override |
| public ElementHandlerBase get() { |
| return new Date(); |
| } |
| }); |
| myElementsMap.put("entry", new Getter<ElementHandlerBase>() { |
| @Override |
| public ElementHandlerBase get() { |
| return new Entry(myBase); |
| } |
| }); |
| myElementsMap.put("target", new Getter<ElementHandlerBase>() { |
| @Override |
| public ElementHandlerBase get() { |
| return new Target(); |
| } |
| }); |
| myElementsMap.put("against", new Getter<ElementHandlerBase>() { |
| @Override |
| public ElementHandlerBase get() { |
| return new Against(); |
| } |
| }); |
| myElementsMap.put("wc-status", new Getter<ElementHandlerBase>() { |
| @Override |
| public ElementHandlerBase get() { |
| return new WcStatus(); |
| } |
| }); |
| } |
| |
| @Override |
| public void endElement(String uri, String localName, String qName) throws SAXException { |
| // |
| } |
| |
| @Override |
| public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { |
| assertSAX(! myParseStack.isEmpty()); |
| ElementHandlerBase current = myParseStack.get(myParseStack.size() - 1); |
| if (mySb.length() > 0) { |
| current.characters(mySb.toString().trim(), myPending, myLockBuilder); |
| mySb.setLength(0); |
| } |
| |
| while (true) { |
| final boolean createNewChild = current.startElement(uri, localName, qName, attributes); |
| if (createNewChild) { |
| assertSAX(myElementsMap.containsKey(qName)); |
| final ElementHandlerBase newChild = myElementsMap.get(qName).get(); |
| newChild.preAttributesEffect(myDataCallback); |
| newChild.updateStatus(attributes, myPending, myLockBuilder); |
| newChild.preEffect(myDataCallback); |
| myParseStack.add(newChild); |
| return; |
| } else { |
| // go up |
| current.postEffect(myDataCallback); |
| myParseStack.remove(myParseStack.size() - 1); |
| assertSAX(! myParseStack.isEmpty()); |
| current = myParseStack.get(myParseStack.size() - 1); |
| } |
| } |
| } |
| |
| @Override |
| public void characters(char[] ch, int start, int length) throws SAXException { |
| assertSAX(! myParseStack.isEmpty()); |
| mySb.append(ch, start, length); |
| } |
| |
| @Override |
| public void endDocument() throws SAXException { |
| assertSAX(! myParseStack.isEmpty()); |
| for (int i = myParseStack.size() - 1; i >= 0; -- i) { |
| ElementHandlerBase current = myParseStack.get(i); |
| current.postEffect(myDataCallback); |
| } |
| myParseStack.clear(); |
| } |
| |
| private static void assertSAX(final boolean shouldBeTrue) throws SAXException { |
| if (! shouldBeTrue) { |
| throw new SAXException("can not parse output"); |
| } |
| } |
| |
| private static StatusType parseContentsStatus(Attributes attributes) throws SAXException { |
| final String item = attributes.getValue("item"); |
| assertSAX(item != null); |
| return getStatus(item); |
| } |
| |
| private static StatusType parsePropertiesStatus(Attributes attributes) throws SAXException { |
| final String props = attributes.getValue("props"); |
| assertSAX(props != null); |
| return getStatus(props); |
| } |
| |
| private static class Fake extends ElementHandlerBase { |
| private Fake() { |
| super(new String[]{"status"}, new String[]{}); |
| } |
| |
| @Override |
| protected void updateStatus(Attributes attributes, PortableStatus status, Lock.Builder lock) throws SAXException { |
| } |
| |
| @Override |
| public void postEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void preEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void characters(String s, PortableStatus pending, Lock.Builder lock) { |
| } |
| } |
| |
| private static class Date extends ElementHandlerBase { |
| private Date() { |
| super(new String[]{}, new String[]{}); |
| } |
| |
| @Override |
| protected void updateStatus(Attributes attributes, PortableStatus status, Lock.Builder lock) throws SAXException { |
| } |
| |
| @Override |
| public void postEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void preEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void characters(String s, PortableStatus pending, Lock.Builder lock) { |
| } |
| } |
| |
| private static class Author extends ElementHandlerBase { |
| private Author() { |
| super(new String[]{}, new String[]{}); |
| } |
| |
| @Override |
| protected void updateStatus(Attributes attributes, PortableStatus status, Lock.Builder lock) throws SAXException { |
| } |
| |
| @Override |
| public void postEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void preEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void characters(String s, PortableStatus pending, Lock.Builder lock) { |
| } |
| } |
| |
| /* <commit |
| revision="25"> |
| <author>admin</author> |
| <date>2011-11-09T12:21:02.401530Z</date> |
| */ |
| private static class Commit extends ElementHandlerBase { |
| private Commit() { |
| super(new String[]{"author", "date"}, new String[]{}); |
| } |
| |
| @Override |
| protected void updateStatus(Attributes attributes, PortableStatus status, Lock.Builder lock) throws SAXException { |
| final String revision = attributes.getValue("revision"); |
| if (!StringUtil.isEmpty(revision)) { |
| status.setCommittedRevision(SVNRevision.create(Long.valueOf(revision))); |
| } |
| } |
| |
| @Override |
| public void postEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void preEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void characters(String s, PortableStatus pending, Lock.Builder lock) { |
| } |
| } |
| |
| /*<lock> |
| <token>opaquelocktoken:27ee743a-5376-fc4a-a209-b7834e1a3f39</token> |
| <owner>admin</owner> |
| <comment>LLL</comment> |
| <created>2012-02-21T09:59:39.771077Z</created> |
| </lock>*/ |
| |
| /*<lock> |
| <token>opaquelocktoken:e21e93d2-0623-b347-bb39-900b01387555</token> |
| <owner>admin</owner> |
| <comment>787878</comment> |
| <created>2012-02-21T10:17:29.160005Z</created> |
| </lock> |
| </wc-status> |
| <repos-status |
| props="none" |
| item="none"> |
| <lock> |
| <token>opaquelocktoken:e21e93d2-0623-b347-bb39-900b01387555</token> |
| <owner>admin</owner> |
| <comment>787878</comment> |
| <created>2012-02-21T10:17:29.160005Z</created> |
| </lock> |
| </repos-status> |
| </entry>*/ |
| |
| private static class LockCreatedDate extends ElementHandlerBase { |
| private LockCreatedDate() { |
| super(new String[]{}, new String[]{}); |
| } |
| |
| @Override |
| protected void updateStatus(Attributes attributes, PortableStatus status, Lock.Builder lock) throws SAXException { |
| } |
| |
| @Override |
| public void postEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void preEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void characters(String s, PortableStatus pending, Lock.Builder lock) { |
| final SVNDate date = SVNDate.parseDate(s); |
| lock.setCreationDate(date); |
| } |
| } |
| |
| private static class LockComment extends ElementHandlerBase { |
| private LockComment() { |
| super(new String[]{}, new String[]{}); |
| } |
| |
| @Override |
| protected void updateStatus(Attributes attributes, PortableStatus status, Lock.Builder lock) throws SAXException { |
| } |
| |
| @Override |
| public void postEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void preEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void characters(String s, PortableStatus pending, Lock.Builder lock) { |
| lock.setComment(s); |
| } |
| } |
| |
| private static class LockOwner extends ElementHandlerBase { |
| private LockOwner() { |
| super(new String[]{}, new String[]{}); |
| } |
| |
| @Override |
| protected void updateStatus(Attributes attributes, PortableStatus status, Lock.Builder lock) throws SAXException { |
| } |
| |
| @Override |
| public void postEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void preEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void characters(String s, PortableStatus pending, Lock.Builder lock) { |
| lock.setOwner(s); |
| } |
| } |
| |
| private static class LockToken extends ElementHandlerBase { |
| private LockToken() { |
| super(new String[]{}, new String[]{}); |
| } |
| |
| @Override |
| protected void updateStatus(Attributes attributes, PortableStatus status, Lock.Builder lock) throws SAXException { |
| } |
| |
| @Override |
| public void postEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void preEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void characters(String s, PortableStatus pending, Lock.Builder lock) { |
| lock.setToken(s); |
| } |
| } |
| |
| private static class LockElement extends ElementHandlerBase { |
| private LockElement() { |
| super(new String[]{"token", "owner", "comment", "created"}, new String[]{}); |
| } |
| |
| @Override |
| protected void updateStatus(Attributes attributes, PortableStatus status, Lock.Builder lock) throws SAXException { |
| } |
| |
| @Override |
| public void postEffect(DataCallback callback) { |
| callback.endLock(); |
| } |
| |
| @Override |
| public void preAttributesEffect(DataCallback callback) { |
| callback.startLock(); |
| } |
| |
| @Override |
| public void preEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void characters(String s, PortableStatus pending, Lock.Builder lock) { |
| } |
| } |
| |
| private static class ReposStatus extends ElementHandlerBase { |
| private ReposStatus() { |
| super(new String[]{"lock"}, new String[]{}); |
| } |
| |
| @Override |
| protected void updateStatus(Attributes attributes, PortableStatus status, Lock.Builder lock) throws SAXException { |
| final StatusType propertiesStatus = parsePropertiesStatus(attributes); |
| status.setRemotePropertiesStatus(propertiesStatus); |
| |
| final StatusType contentsStatus = parseContentsStatus(attributes); |
| status.setRemoteContentsStatus(contentsStatus); |
| } |
| |
| @Override |
| public void postEffect(DataCallback callback) { |
| callback.endRemoteStatus(); |
| } |
| |
| @Override |
| public void preAttributesEffect(DataCallback callback) { |
| callback.startLock(); |
| } |
| |
| @Override |
| public void preEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void characters(String s, PortableStatus pending, Lock.Builder lock) { |
| } |
| } |
| |
| /* <wc-status props="none" copied="true" tree-conflicted="true" item="added"> |
| <wc-status props="none" item="unversioned"> |
| <wc-status props="none" item="added" revision="-1"> |
| <wc-status props="none" item="modified" revision="112"> |
| <wc-status props="conflicted" item="normal" revision="112"> |
| */ |
| private static class WcStatus extends ElementHandlerBase { |
| private WcStatus() { |
| super(new String[]{"commit", "lock"}, new String[]{}); |
| } |
| |
| /*<wc-status |
| props="none" |
| wc-locked="true" |
| item="normal" |
| revision="120">*/ |
| |
| @Override |
| protected void updateStatus(Attributes attributes, PortableStatus status, Lock.Builder lock) throws SAXException { |
| final StatusType propertiesStatus = parsePropertiesStatus(attributes); |
| status.setPropertiesStatus(propertiesStatus); |
| final StatusType contentsStatus = parseContentsStatus(attributes); |
| status.setContentsStatus(contentsStatus); |
| |
| if (StatusType.STATUS_CONFLICTED.equals(propertiesStatus) || StatusType.STATUS_CONFLICTED.equals(contentsStatus)) { |
| status.setIsConflicted(true); |
| } |
| |
| // optional |
| final String locked = attributes.getValue("wc-locked"); |
| if (locked != null && Boolean.parseBoolean(locked)) { |
| status.setIsLocked(true); |
| } |
| final String copied = attributes.getValue("copied"); |
| if (copied != null && Boolean.parseBoolean(copied)) { |
| status.setIsCopied(true); |
| } |
| final String treeConflicted = attributes.getValue("tree-conflicted"); |
| if (treeConflicted != null && Boolean.parseBoolean(treeConflicted)) { |
| status.setIsConflicted(true); |
| } |
| |
| final String switched = attributes.getValue("switched"); |
| if (switched != null && Boolean.parseBoolean(switched)) { |
| status.setIsSwitched(true); |
| } |
| |
| final String revision = attributes.getValue("revision"); |
| if (! StringUtil.isEmptyOrSpaces(revision)) { |
| try { |
| final long number = Long.parseLong(revision); |
| status.setRevision(SVNRevision.create(number)); |
| } catch (NumberFormatException e) { |
| throw new SAXException(e); |
| } |
| } |
| } |
| |
| @Override |
| public void postEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void preEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void characters(String s, PortableStatus pending, Lock.Builder lock) { |
| } |
| } |
| |
| private static class Entry extends ElementHandlerBase { |
| private final File myBase; |
| |
| private Entry(final File base) { |
| super(new String[]{"wc-status", "repos-status"}, new String[]{}); |
| myBase = base; |
| } |
| |
| @Override |
| protected void updateStatus(Attributes attributes, PortableStatus status, Lock.Builder lock) throws SAXException { |
| final String path = attributes.getValue("path"); |
| assertSAX(path != null); |
| final File file = SvnUtil.resolvePath(myBase, path); |
| status.setFile(file); |
| final boolean exists = file.exists(); |
| if (exists) { |
| status.setKind(exists, NodeKind.from(file.isDirectory())); |
| } else { |
| // this is a hack. This is done so because of strange svn native client output: |
| /* |
| c:\TestProjects\sortedProjects\Subversion\local\withExt82420\mod4>svn st --xml |
| <?xml version="1.0" encoding="UTF-8"?> |
| <status> |
| <target |
| path="."> |
| <entry |
| path="mod4"> |
| <wc-status |
| props="none" |
| item="unversioned"> |
| </wc-status> |
| </entry> |
| </target> |
| </status> |
| |
| while |
| |
| c:\TestProjects\sortedProjects\Subversion\local\withExt82420\mod4>dir |
| Volume in drive C has no label. |
| Volume Serial Number is B4EA-B379 |
| |
| Directory of c:\TestProjects\sortedProjects\Subversion\local\withExt82420\mod4 |
| |
| 03/09/2012 05:30 PM <DIR> . |
| 03/09/2012 05:30 PM <DIR> .. |
| 03/09/2012 05:30 PM 437 mod4.iml |
| 03/09/2012 05:30 PM <DIR> src |
| |
| and no "mod4" under |
| |
| */ |
| final StatusType ns = status.getNodeStatus(); |
| if (myBase.getName().equals(path) && ! StatusType.MISSING.equals(ns) && |
| ! StatusType.STATUS_DELETED.equals(ns) ) { |
| status.setKind(true, NodeKind.DIR); |
| status.setFile(myBase); |
| status.setPath(""); |
| return; |
| } |
| status.setKind(exists, NodeKind.UNKNOWN); |
| } |
| status.setPath(path); |
| } |
| |
| @Override |
| public void postEffect(DataCallback callback) { |
| callback.switchPath(); |
| } |
| |
| @Override |
| public void preEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void characters(String s, PortableStatus pending, Lock.Builder lock) { |
| } |
| } |
| |
| private static class Changelist extends ElementHandlerBase { |
| private String myName; |
| |
| private Changelist() { |
| super(new String[]{}, new String[]{"entry"}); |
| } |
| |
| @Override |
| protected void updateStatus(Attributes attributes, PortableStatus status, Lock.Builder lock) throws SAXException { |
| final String name = attributes.getValue("name"); |
| assertSAX(! StringUtil.isEmptyOrSpaces(name)); |
| myName = name; |
| } |
| |
| @Override |
| public void postEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void preEffect(DataCallback callback) { |
| callback.switchChangeList(myName); |
| } |
| |
| @Override |
| public void characters(String s, PortableStatus pending, Lock.Builder lock) { |
| } |
| } |
| |
| private static class Target extends ElementHandlerBase { |
| private Target() { |
| super(new String[]{"against"}, new String[]{"entry"}); |
| } |
| |
| @Override |
| protected void updateStatus(Attributes attributes, PortableStatus status, Lock.Builder lock) { |
| } |
| |
| @Override |
| public void postEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void preEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void characters(String s, PortableStatus pending, Lock.Builder lock) { |
| } |
| } |
| |
| private static class Against extends ElementHandlerBase { |
| private Against() { |
| super(new String[0], new String[0]); |
| } |
| |
| @Override |
| protected void updateStatus(Attributes attributes, PortableStatus status, Lock.Builder lock) throws SAXException { |
| } |
| |
| @Override |
| public void postEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void preEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void characters(String s, PortableStatus pending, Lock.Builder lock) { |
| } |
| } |
| |
| private static class Status extends ElementHandlerBase { |
| private Status() { |
| super(new String[]{"target"}, new String[]{"changelist"}); |
| } |
| |
| @Override |
| protected void updateStatus(Attributes attributes, PortableStatus status, Lock.Builder lock) { |
| } |
| |
| @Override |
| public void postEffect(final DataCallback callback) { |
| } |
| |
| @Override |
| public void preEffect(DataCallback callback) { |
| } |
| |
| @Override |
| public void characters(String s, PortableStatus pending, Lock.Builder lock) { |
| } |
| } |
| |
| public abstract static class ElementHandlerBase { |
| private final Set<String> myAwaitedChildren; |
| private final Set<String> myAwaitedChildrenMultiple; |
| |
| ElementHandlerBase(String[] awaitedChildren, String[] awaitedChildrenMultiple) { |
| myAwaitedChildren = new HashSet<String>(Arrays.asList(awaitedChildren)); |
| myAwaitedChildrenMultiple = new HashSet<String>(Arrays.asList(awaitedChildrenMultiple)); |
| } |
| |
| protected abstract void updateStatus(Attributes attributes, PortableStatus status, Lock.Builder lock) throws SAXException; |
| public abstract void postEffect(final DataCallback callback); |
| public abstract void preEffect(final DataCallback callback); |
| |
| public boolean startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { |
| if (myAwaitedChildrenMultiple.contains(qName)) { |
| return true; |
| } |
| return myAwaitedChildren.remove(qName); |
| } |
| |
| public abstract void characters(String s, PortableStatus pending, Lock.Builder lock); |
| |
| public void preAttributesEffect(DataCallback callback) {} |
| } |
| |
| public interface ExternalDataCallback { |
| void switchPath(); |
| void switchChangeList(final String newList); |
| } |
| |
| private interface DataCallback extends ExternalDataCallback { |
| void startRemoteStatus(); |
| void endRemoteStatus(); |
| void startLock(); |
| void endLock(); |
| void switchPath(); |
| void switchChangeList(final String newList); |
| } |
| } |