Долго размышляя над этой проблемой, я в конце концов решил ее сам. Это решение предполагает, что в вашем проекте есть библиотека Tapestry-Spring.
В моем случае у меня есть компонент Spring, который содержит некоторые глобальные свойства моего приложения:
package myapp;
public class AppProperties {
private String build;
public String getBuild() {
return build;
}
public void setBuild(String build) {
this.build = build;
}
// other properties
}
Объявите этот bean-компонент в конфигурации Spring:
<bean id="appProperties" class="myapp.AppProperties">
<property name="build" value="@BUILD_NUMBER@"/>
</bean>
Вы можете настроить скрипт сборки Ant для замены @BUILD_NUMBER@
фактическим числом (см. Копировать задачу в руководстве Ant для получения подробной информации).
Теперь создайте класс, который будет обертывать IAsset
s, и прикрепите номер сборки к URL-адресу:
package myapp;
import java.io.InputStream;
import org.apache.hivemind.Location;
import org.apache.hivemind.Resource;
import org.apache.tapestry.IAsset;
public class BuildAwareAssetWrapper implements IAsset {
private IAsset wrapped;
private String build;
public BuildAwareAssetWrapper(IAsset wrapped, String build) {
this.wrapped = wrapped;
this.build = build;
}
public String buildURL() {
return addParam(wrapped.buildURL(), "build", build);
}
public InputStream getResourceAsStream() {
return wrapped.getResourceAsStream();
}
public Resource getResourceLocation() {
return wrapped.getResourceLocation();
}
public Location getLocation() {
return wrapped.getLocation();
}
private static String addParam(String url, String name, String value) {
if (url == null) url = "";
char sep = url.contains("?") ? '&' : '?';
return url + sep + name + '=' + value;
}
}
Далее нам нужно заставить Tapestry обернуть все активы нашей оберткой. Класс AssetSourceImpl
отвечает за предоставление IAsset
экземпляров Tapestry. Мы расширим этот класс и переопределим метод findAsset()
, чтобы мы могли обернуть созданные активы классом-оболочкой:
package myapp;
import java.util.Locale;
import org.apache.hivemind.Location;
import org.apache.hivemind.Resource;
import org.apache.tapestry.IAsset;
import org.apache.tapestry.asset.AssetSourceImpl;
public class BuildAwareAssetSourceImpl extends AssetSourceImpl {
private AppProperties props;
@Override
public IAsset findAsset(Resource base, String path, Locale locale, Location location) {
IAsset asset = super.findAsset(base, path, locale, location);
return new BuildAwareAssetWrapper(asset, props.getBuild());
}
public void setAppProperties(AppProperties props) {
this.props = props;
}
}
Обратите внимание, что в реализации есть сеттер, который может принимать наш компонент Spring. Последний шаг — заставить Tapestry использовать BuildAwareAssetSourceImpl
для создания ресурсов вместо AssetSourceImpl
. Мы делаем это, переопределяя соответствующую точку обслуживания в hivemodule.xml
:
<!-- Custom asset source -->
<implementation service-id="tapestry.asset.AssetSource">
<invoke-factory service-id="hivemind.BuilderFactory" model="singleton">
<construct class="myapp.BuildAwareAssetSourceImpl">
<set-object property="appProperties" value="spring:appProperties"/>
<set-configuration property="contributions" configuration-id="tapestry.asset.AssetFactories"/>
<set-service property="lookupAssetFactory" service-id="tapestry.asset.LookupAssetFactory"/>
<set-service property="defaultAssetFactory" service-id="tapestry.asset.DefaultAssetFactory"/>
</construct>
</invoke-factory>
</implementation>
Вот и все. Если вы запустите свое приложение и просмотрите исходный код любой страницы, использующей ресурс, вы увидите, что URL-адрес будет иметь новый параметр build
.
person
Robert J. Walker
schedule
25.02.2009