JAX-WS и веб-служба группы пользователей SharePoint - PullRequest
3 голосов
/ 23 сентября 2010

У меня есть небольшое приложение, которое запрашивает интерфейс веб-службы нашего сервера SharePoint для получения списка всех пользователей группы.Я вижу, что необработанный HTTP-ответ возвращается со всеми перечисленными пользователями, но объект ответа JAX-WS (созданный в NetBeans 6.9) содержит только пустое значение Group Name String.В ответе HTTP нет никаких следов всех имен пользователей.

Кто-нибудь знает, почему JAX-WS неправильно читает в ответе SOAP?

WSDL слишком длинный для публикации, ношироко доступен из разных мест, включая этот сайт: http://www.hezser.de/_vti_bin/UserGroup.asmx?wsdl

Вот начало необработанного HTTP-ответа:

---[HTTP response - http://{server}/_vti_bin/usergroup.asmx - 200]---
null: HTTP/1.1 200 OK
Cache-control: private, max-age=0
Content-type: text/xml; charset=utf-8
Content-length: 136738
X-powered-by: ASP.NET
Server: Microsoft-IIS/6.0
Date: Wed, 22 Sep 2010 20:53:12 GMT
X-aspnet-version: 2.0.50727
Set-cookie: WSS_KeepSessionAuthenticated=80; path=/
Microsoftsharepointteamservices: 12.0.0.6303
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><GetUserCollectionFromGroupResponse xmlns="http://schemas.microsoft.com/sharepoint/soap/directory/"><GetUserCollectionFromGroupResult><GetUserCollectionFromGroup><Users><User ID="201" Sid="S-1-5-21-1545385408-2720673749-3828181483-1245" ....

Ответы [ 3 ]

3 голосов
/ 13 ноября 2010

Вам необходимо отредактировать UserGroup.wsdl вручную перед созданием заглушек.Вам необходимо добавить processContents='skip' к тегу <s:any>, в котором определен ответ.

<s:element name="GetUserCollectionFromGroupResponse">
 <s:complexType>
  <s:sequence>
    <s:element minOccurs="0" maxOccurs="1" name="GetUserCollectionFromGroupResult">
      <s:complexType mixed="true">
        <s:sequence>
          <!-- Added the "processContents" attribute below -->
          <s:any processContents='skip' />    
        </s:sequence>
      </s:complexType>
    </s:element>
  </s:sequence>
 </s:complexType>
</s:element>

Затем при обработке ответа JAXB вернет дочерние элементы в качестве элементов DOM:

UserGroup service = new UserGroup();
UserGroupSoap port = service.getUserGroupSoap();

GetUserCollectionFromGroupResult usersCollection = port.getUserCollectionFromGroup(Settings.usersGroup);
List<Object> content = usersCollection.getContent();
org.w3c.dom.Element usersElement = (org.w3c.dom.Element) content.get(0);

Почему это работает

Проблема вызвана сочетанием условий:

A.Ответ, возвращаемый веб-службой, содержит тег <GetUserCollectionFromGroup>:

<GetUserCollectionFromGroupResult>
    <GetUserCollectionFromGroup>
       <Users>
          <User ID="4" Name="User1_Display_Name" />
          <User ID="5" Name="User2_Display_Name" />
       </Users>
    </GetUserCollectionFromGroup>
</GetUserCollectionFromGroupResult>

B.Схема, встроенная в WSDL, определяет <GetUserCollectionFromGroup> как содержащий один дочерний элемент, <groupName> (это элемент, используемый для выполнения запроса):

<s:element name="GetUserCollectionFromGroup">
  <s:complexType>
    <s:sequence>
      <s:element minOccurs="0" maxOccurs="1" name="groupName" type="s:string"/>
    </s:sequence>
  </s:complexType>
</s:element>

C.JAXB учитывает атрибут processContents <xs:any> (см. Отображение).Когда processContents='strict', JAXB пытается сопоставить (и маршаллизировать) дочерние элементы на основе пространства имен, к которому они принадлежат.

D.Определение схемы WSDL для <GetUserCollectionFromGroupResult> включает <xs:any>:

<s:element name="GetUserCollectionFromGroupResponse">
 <s:complexType>
  <s:sequence>
    <s:element minOccurs="0" maxOccurs="1" name="GetUserCollectionFromGroupResult">
      <s:complexType mixed="true">
        <s:sequence>
          <s:any/>
        </s:sequence>
      </s:complexType>
    </s:element>
  </s:sequence>
 </s:complexType>
</s:element>

E.Если processContents опущено, по умолчанию используется значение strict.

. Таким образом, когда JAX-WS / JAXB обрабатывает результаты веб-службы, он пытается маршалировать дочерние элементы <GetUserCollectionFromGroupResult>, используя схему.Дочерние элементы отображаются в ответе как принадлежащие к тому же пространству имен, что и запрос.Когда элемент <GetUserCollectionFromGroup> обрабатывается, он направляется в экземпляр того же класса, который использовался в запросе для элемента <GetUserCollectionFromGroup>.Таким образом, вы фактически заблокированы от получения элементов <Users>.

Я искал максимумы и минимумы, и единственное решение (я), которое я могу найти, - это эфир (а) отредактировать WSDL какописано в начале этого ответа, или (б) редактировать сгенерированные заглушки.Не идеально, но неизбежно в этом случае.

Дополнительную информацию об элементе схемы <xs:any> (и атрибуте processContents) можно найти в MSDN здесь .

0 голосов
/ 25 сентября 2010

Спасибо за ответ.Вы правы, я должен был опубликовать сгенерированный код, но вызов и ответ были настолько простыми, что я даже не думал об этом.Упрощенные вызовы:

    System.setProperty("com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump", "true");
    GetUserCollectionFromGroupResult usersCollection = null;

    Object o = null;
    UserGroup service = new UserGroup();
    UserGroupSoap port = service.getUserGroupSoap();

    usersCollection = port.getUserCollectionFromGroup(Settings.usersGroup);

Возвращенная коллекция usersCollection содержит только один элемент, который представляет собой «groupName» со значением «null».

К сожалению, Microsoft, похоже, любит использовать ЛЮБОЙ элемент почтивсе их определения WSDL.У меня есть несколько рабочих, включая Аутентификацию, Веб, Списки, Версии, но эта просто не пойдет.

Я думаю, что можно переписать код получателя по умолчанию, но ранее сегодня я решил, что, вероятно, будет прощепросто написать свой собственный простой SOAP-клиент, а не пытаться выяснить, как исправить приемник JAX-WS.Так что, хотя это, вероятно, не самый правильный подход, он сделал свою работу.Вот код во всем этом ужас.

Я новичок в Java, так что будьте спокойны со мной; -)

    HashMap<String, String> users = null;
    String SOAPUrl = Settings.userListWebServiceURL;
    String SOAPAction = "http://schemas.microsoft.com/sharepoint/soap/directory/GetUserCollectionFromGroup";

    // Create the connection.
    URL url = new URL(SOAPUrl);
    URLConnection connection = url.openConnection();
    HttpURLConnection httpConn = (HttpURLConnection) connection;

    StringBuilder sb = new StringBuilder();
    sb.append("<?xml version=\"1.0\" ?><S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\"><S:Body><GetUserCollectionFromGroup xmlns=\"http://schemas.microsoft.com/sharepoint/soap/directory/\"><groupName>");
    sb.append(Settings.usersGroup);
    sb.append("</groupName></GetUserCollectionFromGroup></S:Body></S:Envelope>");

    byte[] b = sb.toString().getBytes("UTF-8");

    // Set the appropriate HTTP parameters.
    httpConn.setRequestProperty("Content-Length", String.valueOf( b.length ) );
    httpConn.setRequestProperty("Content-Type","text/xml; charset=utf-8");
    httpConn.setRequestProperty("SOAPAction",SOAPAction);
    httpConn.setRequestMethod( "POST" );
    httpConn.setDoOutput(true);
    httpConn.setDoInput(true);

    // Everything's set up; send the XML that was read in to b.
    OutputStream out = httpConn.getOutputStream();
    out.write( b );
    out.flush();
    out.close();

    // Setup to receive the result and convert stream to DOM Document
    DOMParser parser = new DOMParser();
    InputStreamReader in = new InputStreamReader(httpConn.getInputStream());
    InputSource source = new InputSource(in);
    parser.parse(source);
    org.w3c.dom.Document d = parser.getDocument();
    in.close();
    httpConn.disconnect();

    // Read the DOM and contruct a Hashmap with username to e-mail mapping.
    NodeList nl = d.getElementsByTagName("User");
    users = new HashMap<String, String>();
    for (int i = 0; i < nl.getLength(); i++) {
        NamedNodeMap attr = nl.item(i).getAttributes();
        users.put(attr.getNamedItem("LoginName").getNodeValue(), attr.getNamedItem("Email").getNodeValue());
    }
0 голосов
/ 24 сентября 2010

На ваш вопрос довольно сложно ответить, потому что мы не видим сгенерированный клиент, который вы используете, ни сообщения об отладке / ошибках при вызове, но я попробую. Ваш WSDL выглядит корректным, и если ваш стек инструментов JAX-WS способен создать клиента (с соответствующими классами Java) и способен правильно вызывать конечную точку, вы до сих пор хорошо справились.

Если посмотреть на HTTP-ответ и ваш WSDL, ваш SOAP-запрос был GetUserCollectionFromGroup . Глядя на определение XML-схемы (в WSDL) GetUserCollectionFromGroupResponse Я озадачен одной вещью:

 <s:element name="GetUserCollectionFromGroupResponse"> 
    <s:complexType> 
      <s:sequence> 
        <s:element minOccurs="0" maxOccurs="1" name="GetUserCollectionFromGroupResult"> 
          <s:complexType mixed="true"> 
            <s:sequence> 
              <s:any /> 
            </s:sequence> 
          </s:complexType> 
        </s:element> 
      </s:sequence> 
    </s:complexType> 
  </s:element>

WSDL в основном говорит, что ваш вызов может вернуть любой тип XML. То, что вы получили от веб-сервиса - это кусок XML, такой как:

<users><user ID="201" Sid="" /></users>

Конечно, это подходит под описание любого вида XML, но я думаю, что ваш сгенерированный клиент испытывает проблемы с его пониманием. Теперь у меня нет опыта работы с набором инструментов jax-ws в NetBeans 6.9, но вы должны сконфигурировать генерацию WSDL-to-client таким образом, чтобы он преобразовывал это «любое» в элемент XML Java или XML XML Java. Узел объекта.

Как выглядит сгенерированный код для этого вызова? Неужели вы думаете, что вы получите String пользователя обратно?

...