Установка ETAG/LastModified для представления, отправленного ServerResource

Я знаю, что могу установить свойства ETAG и LastModified на Представление / Представление Info. Но у меня есть простой ресурс, реализованный так:

public class AccountServerResource extends ServerResource implements AccountResource {

    private static Logger log = Logger.getLogger(Acc​ountServerResource.c​lass.getName());

    @Override
    public Account retrieve() {
        User user = getClientInfo().getUser();
        AccountDAO dao = new AccountDAO();
        Account ret = dao.getAccountByEmai​l(user.getEm​ail());
        log.info("retrieved " + ret);
        // getResponse().getEntity() == null at this point !!!
        // ---> cannot do this : getResponse().getEntity().setModificationDate(ret.getLastMod​ified());
        return ret;
    }   
}

Представление еще не прикреплено к ответу в настоящее время. Когда / как мне установить теги ETAG/LastModified?

Какова рекомендуемая практика здесь?

---ОБНОВИТЬ---

Я попробовал этот подход без удачи:

@Override
public Account retrieve() {
        User user = getClientInfo().getUser();
    AccountDAO dao = new AccountDAO(user.getN​amespace());
        AccountDAO dao = new AccountDAO();
        Account ret = dao.getAccountByEmai​l(user.getEm​ail());
    log.info("retrieved " + ret);
    setOnSent(new StrongEtagCallback​<Account>(ret));​
    return ret;
}

И реализация StrongEtagCallback выглядит так:

public class StrongEtagCallback<T extends DomainResource> implements Uniform {

    private static SimpleDateFormat df = new SimpleDateFormat("dd​MMyyyyHHmmssSSS");
    private DomainResource d;

    public StrongEtagCallback(T domainResource) {
        d = domainResource;
    }

    @Override
    public void handle(Request request, Response response) {
        String eTag = d.getClass().getSimpleName() + "-" + d.getId() + "-" + df.format(d.getLastModified());
        response.getEntity().setTag(new Tag(eTag, false));
    }
}

Где все мои сущности реализуют DomainResource, которые требуют, чтобы у них были ID и LastModified дата.

Но это не работает. Я действительно ожидал, что это сработает, это очень элегантно!

Тем не менее вызывается StrongEtagCallback, ETAG устанавливает серверную часть объекта. Мой Wireshark и мой клиент GWT не видят заголовок E-TAG в ответе на ответ. Дайвинг глубже сейчас.

2 ответа

Решение

При исследовании этой проблемы я заметил параллельный поток, запущенный koma на доске обсуждений Restlet, в котором Тим Пайерлс предложил альтернативное и предпочтительное решение, а именно переопределение Resource.toRepresentation().

Как Кома указал в этой теме, переопределение ServerResource.handle() вызвало сбой соответствия условий (я не уверен почему?), поэтому такой подход проблематичен.

Пример кода переопределения, предоставленного Тимом Пайерлсом:

@Override public Representation toRepresentation(Object source, Variant target) {
    Representation rep = super.toRepresentation(source, target);
    if (source instanceof HasLastModified) {
        HasLastModified hlm = (HasLastModified) source;
        rep.setModificationDate(hlm.getLastModified());
    }
    if (source instanceof HasEtag) {
        HasEtag he = (HasEtag) source;
        rep.setTag(he.gettag());
    }
    return rep;
}

Окончательное решение состояло в том, чтобы сделать объект возвращаемого домена локальной переменной и переопределить метод handle() ServerResource. Это безопасно, потому что Javadoc утверждает, что:

один экземпляр ServerResource создается для каждого вызова, обрабатываемого и доступного только одним потоком за раз

Таким образом, реализация выглядит так:

private Account ret = null;

@Override
public Account retrieve() {
    User user = getClientInfo().getUser();
    AccountDAO dao = new AccountDAO();
    ret = dao.getAccountByEmail(UserServiceFactory.getUserService().getCurrentUser().getEmail());
    // getResponse().getEntity().setModificationDate(ret.getLastModified());
    // lastModified = ret.getLastModified();
    log.info("retrieved " + ret);
    //setOnSent(new StrongEtagCallback<Account>(ret));
    return ret;
}

@Override
public Representation handle() {
    Representation representation = super.handle();
    if (ret != null) {
        new StrongEtagCallback<Account>(ret).handle(getRequest(), getResponse());
    }
    return representation;
}

Заголовок ETAG теперь отправлен:

HTTP/1.1 200 OK
Content-Type: application/x-java-serialized-object+gwt; charset=UTF-8
ETag: "Account-104-27012012003721199"
Date: Thu, 26 Jan 2012 23:44:32 GMT
Accept-Ranges: bytes
Server: Restlet-Framework/2.1rc1
Transfer-Encoding: chunked

PS: мое первое решение, которое устанавливает обратный вызов setOnSent после принятия ответа, поэтому это решение не сработало. Я на самом деле ожидал бы подобный крюк или какой-то setNext() Рестлет для постобработки. В конце концов, обратный вызов реализует Uniform интерфейс. ИМО, это лучше вписалось бы в общую архитектуру Рестлета.

Другие вопросы по тегам