Ok, it seems that zip-files aren't approved by our mailserver ...
In the file AbstractRDBMSStore this was added:
// TODO: Added method. Maybe a bad idea to expose this variable?
public RDBMSAdapter getAdapter() {
return adapter;
}
--------------------------------------------
In the file RDBMSExpressionFactory this method was modified:
protected ComparableResourcesPool getRequestedResourcePool() {
if (requestedResourcePool == null) {
// TODO: Add comment here.
// TODO: Add more pools here if need be ...
if (_store.getAdapter() instanceof MySql41RDBMSAdapter) {
requestedResourcePool = new
MySql41ComparableResourcesPool(_store, _context, getQuery());
}
else {
requestedResourcePool = new
RDBMSComparableResourcesPool(_store, _context, getQuery());
}
}
return requestedResourcePool;
}
------------------------------------------------------
The file MySql41ComparableResourcesPool.java was created and looks like
this:
/*
* $Header:
/home/cvs/jakarta-slide/src/stores/org/apache/slide/store/impl/rdbms/MySql41
ComparableResourcesPool.java,v 1.10.2.4 2004/10/27 12:58:41 unico Exp $
* $Revision: 1.10.2.4 $
* $Date: 2004/10/27 12:58:41 $
*
* ====================================================================
*
* Copyright 1999-2004 The Apache Software Foundation
*
* 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.apache.slide.store.impl.rdbms;
import java.lang.reflect.Constructor;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.apache.slide.common.PropertyName;
import org.apache.slide.common.RequestedProperties;
import org.apache.slide.common.RequestedProperty;
import org.apache.slide.common.RequestedPropertyImpl;
import org.apache.slide.common.ServiceAccessException;
import org.apache.slide.common.SlideException;
import org.apache.slide.common.SlideRuntimeException;
import org.apache.slide.content.NodeProperty;
import org.apache.slide.search.BadQueryException;
import org.apache.slide.search.PropertyProvider;
import org.apache.slide.search.QueryScope;
import org.apache.slide.search.SearchQuery;
import org.apache.slide.search.SearchToken;
import org.apache.slide.search.basic.ComparableResourceImpl;
import org.apache.slide.search.basic.ComparableResourcesPool;
import org.apache.slide.search.basic.IBasicQuery;
import org.apache.slide.security.AccessDeniedException;
import org.apache.slide.store.impl.rdbms.expression.RDBMSExpressionFactory;
import org.apache.slide.store.impl.rdbms.expression.RDBMSQueryContext;
import org.apache.slide.structure.ObjectNode;
import org.apache.slide.util.logger.Logger;
/**
*/
public class MySql41ComparableResourcesPool extends
RDBMSComparableResourcesPool {
private final AbstractRDBMSStore _store;
private final RDBMSQueryContext _context;
private final IBasicQuery _query;
private final SearchToken _token;
private final QueryScope _scope;
private final Map _selectProperties;
private final PropertyProvider _provider;
private Set _pool;
public MySql41ComparableResourcesPool(AbstractRDBMSStore store,
RDBMSQueryContext context,
IBasicQuery query) {
super(store, context, query);
_store = store;
_context = context;
_query = query;
_token = _query.getSearchToken();
_scope = _query.getScope();
_selectProperties = new HashMap();
_provider = new RDBMSPropertyProvider(_query.getPropertyProvider(),
_selectProperties);
if (_query instanceof SearchQuery) {
final RequestedProperties props = ((SearchQuery)
_query).requestedProperties();
if (!props.isAllProp()) {
final Iterator iter = props.getRequestedProperties();
while (iter.hasNext()) {
final RequestedProperty property = (RequestedProperty)
iter.next();
final String selectKey = property.getNamespace() +
property.getName();
if (_context.selects().containsKey(selectKey)) {
_selectProperties.put(property, new HashMap());
}
}
}
}
}
public Iterator resourceIterator() {
try {
return getPool().iterator();
}
catch (BadQueryException e) {
throw new SlideRuntimeException(e.toString());
}
}
public Set getPool() throws BadQueryException {
if (_pool == null) {
try {
// TODO: Fix comments to this
if (_query.isLimitDefined()) {
int limit = _query.getLimit();
int loopCount = 0;
_pool = new HashSet(limit);
while (_pool.size() < limit) {
ObjectNode[] objects = retrieveObjects(loopCount *
limit);
for (int i = 0; (i < objects.length) &&
(_pool.size() < limit); i++) {
try {
_pool.add(new
ComparableResourceImpl(objects[i], _token, _scope, _provider));
}
catch (AccessDeniedException e) {
// ignore: object is not visible
}
}
// Don't continue loop if the number of returned
hits is
// below the limit!!
if (objects.length < limit) {
break;
}
}
}
else {
super.getPool();
}
}
catch (ServiceAccessException e) {
throw new BadQueryException(e);
}
catch (SlideException e) {
throw new BadQueryException(e);
}
}
return _pool;
}
public boolean partialResult() {
return false;
}
public QueryScope getScope() {
return _scope;
}
private ObjectNode[] retrieveObjects(int limitOffset) throws
ServiceAccessException, BadQueryException {
if (_store.getCurrentlyActiveTransactionalResource() == null) {
Connection connection = null;
try {
connection = _store.getNewConnection();
return retrieveObjects(connection, limitOffset);
} catch (SQLException e) {
throw new ServiceAccessException(_store, e);
} finally {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
_store.getLogger().log(e,
AbstractRDBMSStore.LOG_CHANNEL, Logger.WARNING);
}
}
}
} else {
return retrieveObjects(_store.getCurrentConnection(),
limitOffset);
}
}
private ObjectNode[] retrieveObjects(Connection connection, int
limitOffset) throws ServiceAccessException, BadQueryException {
PreparedStatement statement = null;
ResultSet result = null;
ArrayList classNames = new ArrayList();
ArrayList uris = new ArrayList();
try {
final String sql = compileSQL(limitOffset);
if (_store.getLogger().isEnabled(Logger.INFO)) {
_store.getLogger().log("executing: " + sql,
AbstractRDBMSStore.LOG_CHANNEL, Logger.INFO);
}
statement = connection.prepareStatement(sql);
result = statement.executeQuery();
while (result.next()) {
final String uri = result.getString(1);
final String className = result.getString(2);
uris.add(uri);
classNames.add(className);
Iterator iter = _selectProperties.keySet().iterator();
while (iter.hasNext()) {
final RequestedProperty requested = (RequestedProperty)
iter.next();
final String name = requested.getName();
final String namespace = requested.getNamespace();
final String alias =
RDBMSExpressionFactory.propertyToAlias(requested.getName());
final String value = result.getString(alias);
final NodeProperty property = new NodeProperty(name,
value, namespace);
final Map properties = (Map)
_selectProperties.get(requested);
properties.put(uri, property);
}
}
}
catch (SQLException e) {
throw new ServiceAccessException(_store, e);
}
finally {
if (result != null) {
try {
result.close();
}
catch (SQLException e) {
_store.getLogger().log(e,
AbstractRDBMSStore.LOG_CHANNEL, Logger.WARNING);
}
}
if (statement != null) {
try {
statement.close();
}
catch (SQLException e) {
_store.getLogger().log(e,
AbstractRDBMSStore.LOG_CHANNEL, Logger.WARNING);
}
}
}
int size = uris.size();
ObjectNode[] objects = new ObjectNode[size];
for (int i = 0; i < size; i++) {
try {
Class objclass = Class.forName((String) classNames.get(i));
Class argClasses[] = { String.class };
Object arguments[] = { uris.get(i) };
Constructor constructor =
objclass.getConstructor(argClasses);
objects[i] = (ObjectNode)
constructor.newInstance(arguments);
objects[i].setUri(objects[i].getUuri());
} catch (Exception e) {
throw new ServiceAccessException(_store, e);
}
}
return objects;
}
private String compileSQL(int limitOffset) throws BadQueryException {
String uri =
_token.getSlideContext().getSlidePath(_scope.getHref());
if (uri.endsWith("/")) {
uri = uri.substring(0, uri.length()-1);
}
String query = "select " + compileSelect() +
" from " + compileJoins() +
" where " + compileScope(uri);
final String criteria = compileCriteria();
query = (criteria != null && criteria.length() > 0) ? query + " AND
" + criteria : query;
query = query + " limit " + limitOffset + "," + _query.getLimit();
return query;
}
private String compileSelect() {
String select = "u.URI_STRING, o.CLASS_NAME";
final Iterator iter = _selectProperties.keySet().iterator();
while (iter.hasNext()) {
final RequestedProperty property = (RequestedProperty)
iter.next();
final String selectKey = property.getNamespace() +
property.getName();
String propSelect = (String) _context.selects().get(selectKey);
if (propSelect != null) {
select += ", " + propSelect;
}
}
return select;
}
private String compileScope(String uri) {
switch (_scope.getDepth()) {
case QueryScope.DEPTH_0: {
return " u.URI_STRING = '" + uri + "'";
}
case QueryScope.DEPTH_1: {
return " (u.URI_STRING = '" + uri + "'" +
" OR (u.URI_STRING LIKE '" + uri + "/%'" +
" AND u.URI_STRING NOT LIKE '" + uri +
"/%/%'))";
}
case QueryScope.DEPTH_INFINITY:
default: {
return " (u.URI_STRING = '" + uri + "'" +
" OR u.URI_STRING LIKE '" + uri + "/%')";
}
}
}
private String compileCriteria() {
String result = null;
if (_context.criteria().size() > 0) {
result = "";
Iterator iter = _context.criteria().iterator();
while (iter.hasNext()) {
result += iter.next();
}
}
return result;
}
private String compileJoins() {
String joins = "((OBJECT o " +
"inner join URI u on u.URI_ID = o.URI_ID) " +
"inner join VERSION_HISTORY vh on vh.URI_ID =
u.URI_ID) ";
Iterator iter = _context.joins().iterator();
while (iter.hasNext()) {
joins = "(" + joins + " " + iter.next() + ") ";
}
return joins;
}
private static class RDBMSPropertyProvider implements PropertyProvider {
private final PropertyProvider _propertyProvider;
private final Map _selectProperties;
private RDBMSPropertyProvider(PropertyProvider propertyProvider, Map
selectProperties) {
_propertyProvider = propertyProvider;
_selectProperties = selectProperties;
}
public boolean isSupportedProperty(String resourceUri, String
propertyName, String propertyNamespace) throws SlideException {
if (_selectProperties.containsKey(new
RequestedPropertyImpl(propertyName, propertyNamespace))) {
return true;
}
else if (_propertyProvider != null) {
return _propertyProvider.isSupportedProperty(resourceUri,
propertyName, propertyNamespace);
}
return false;
}
public Iterator getSupportedPropertiesNames(String resourceUri)
throws SlideException {
Iterator selected = _selectProperties.keySet().iterator();
Iterator provided = null;
if (_propertyProvider != null) {
provided =
_propertyProvider.getSupportedPropertiesNames(resourceUri);
}
return new PropertyNamesIterator(selected, provided);
}
public NodeProperty getProperty(String resourceUri, String
propertyName, String propertyNamespace) throws SlideException {
Map properties = (Map) _selectProperties.get(new
RequestedPropertyImpl(propertyName, propertyNamespace));
if (properties != null) {
return (NodeProperty) properties.get(resourceUri);
}
else if (_propertyProvider != null) {
return _propertyProvider.getProperty(resourceUri,
propertyName, propertyNamespace);
}
return null;
}
public Iterator getSupportedProperties(String resourceUri) throws
SlideException {
Iterator selected = _selectProperties.values().iterator();
Iterator provided = null;
if (_propertyProvider != null) {
provided =
_propertyProvider.getSupportedProperties(resourceUri);
}
return new NodePropertiesIterator(resourceUri, selected,
provided);
}
private static class PropertyNamesIterator implements Iterator {
private final Iterator _selectedProperties;
private final Iterator _providedProperties;
private PropertyNamesIterator(Iterator selectedProperties,
Iterator providedProperties) {
_selectedProperties = selectedProperties;
if (providedProperties != null) {
_providedProperties = providedProperties;
}
else {
_providedProperties = Collections.EMPTY_LIST.iterator();
}
}
public void remove() {
throw new UnsupportedOperationException();
}
public boolean hasNext() {
return _selectedProperties.hasNext() ||
_providedProperties.hasNext();
}
public Object next() {
if (_selectedProperties.hasNext()) {
RequestedProperty property = (RequestedProperty)
_selectedProperties.next();
return new PropertyName(property.getName(),
property.getNamespace());
}
return _providedProperties.next();
}
}
private static class NodePropertiesIterator implements Iterator {
private String _resourceUri;
private Iterator _selectedProperties;
private Iterator _providedProperties;
private NodePropertiesIterator(String resourceUri, Iterator
selectedProperties, Iterator providedProperties) {
_resourceUri = resourceUri;
_selectedProperties = selectedProperties;
if (providedProperties != null) {
_providedProperties = providedProperties;
}
else {
_providedProperties = Collections.EMPTY_LIST.iterator();
}
}
public void remove() {
throw new UnsupportedOperationException();
}
public boolean hasNext() {
return _selectedProperties.hasNext() ||
_providedProperties.hasNext();
}
public Object next() {
if (_selectedProperties.hasNext()) {
Map properties = (Map) _selectedProperties.next();
return (NodeProperty) properties.get(_resourceUri);
}
return _providedProperties.next();
}
}
}
}
------------------------
That's it ... Hopefully this will work ...
Best regards,
Pontus
> -----Original Message-----
> From: Pontus Strand [mailto:[EMAIL PROTECTED]
> Sent: Tuesday, January 18, 2005 2:06 PM
> To: 'Slide Users Mailing List'
> Subject: RE: Slide search performance issues
>
>
> I have been asked to post my changes, please note that I
> consider this a
> quick fix or even a hack.
>
> The basic idea behind it is that the ComparableResourcesPool used is
> specific to each database. In order to solve this the method
> getRequestedResourcePool() in RDBMSExpressionFactory was
> modified to check
> which RDBMS-adapter is used. To achieve that I hade to modify
> AbstractRDBMSStore to return the adapter, i.e. I added the method
> getAdapter(). I'm not sure this is a good solution, hence my
> designation of
> this as a hack.
>
> Finally I added the class MySql41ComparableResourcesPool, that is an
> extension of RDBMSComparableResourcesPool. The class is
> basically a copy of
> RDBMSComparableResourcesPool, but with a few small
> differences. The method
> getPool() check to see if a limit has been requested, if so
> it tries to
> retrieve objects matching the limit. Worth noting is that the
> SQL-query can
> return documents that the user doesn't have access to. So in
> order to get
> the right amount of documents the SQL-query is asked as many
> times as needed
> to get either the requested limit or until no more results
> can be found.
>
> The other major method that was changed is compileSQL(), this
> method was
> modified to include the "limit"-clause. Also, the
> retrieveObjects()-method
> where modified to take the current starting offset as a parameter, a
> parameter that is passed on to compileSQL().
>
> I hope this desciption is good enough to understand the
> changes made and the
> logic behind those changes. Perhaps a seed has been planted
> so that someone
> can implement a more thought through solution.
>
> Best regards,
> Pontus
>
> > -----Original Message-----
> > From: Pontus Strand [mailto:[EMAIL PROTECTED]
> > Sent: Tuesday, January 18, 2005 10:04 AM
> > To: 'Slide Users Mailing List'
> > Subject: RE: Slide search performance issues
> >
> >
> > So I guess one wouldn't have to have an Exchange Server in order to
> > implement those extensions? I'm not too happy about using
> proprietary
> > extensions to a standard, but sometimes you have to be a
> > realist and accept
> > things...
> >
> > Anyway, we have solved to problem by modifying the source to
> > Slide. This is
> > not a good way to solve the problem, as upgrades to newer
> > versions of Slide
> > will be difficult but it was necessary to get the
> performance we need.
> > Basically what we did was to add a MySQL-specific
> > ComparableResourcesPool
> > that adds the keyword "limit" to the select statement. This
> > was a quick fix
> > to a serious problem so it not thought through all the way
> > yet so maybe we
> > will do something else in the future.
> >
> > Regards,
> > Pontus
> >
> > > -----Original Message-----
> > > From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]
> > > Sent: Monday, January 17, 2005 3:37 PM
> > > To: 'Slide Users Mailing List'
> > > Subject: AW: Slide search performance issues
> > >
> > >
> > > My favourite approach concerning this issue would be to
> > implement the
> > > MS-Exchange extension that adds the ability to specify to
> > > limit the result
> > > set by specifying ranges of results.
> > > This is described at the MS WebDAV pages as far as I
> > > remember. But it is not
> > > that easy to implement that on server side. But in fact would
> > > lead a big
> > > step towards Exchange compatibility...
> > > I know that everybody hates MS to extend the standards, but
> > > in the area of
> > > WebDAV they've added some useful bits. So why not adopt it?
> > > Some ranges could be mapped to sql commands by retrieving
> > > only the first
> > > rows, others could at least be filtered at java result set
> > > level. Any ideas?
> > >
> > > Cheers,
> > > Daniel
> > >
> > > > -----Urspr�ngliche Nachricht-----
> > > > Von:
> > [EMAIL PROTECTED]
> > > >
> > > [mailto:[EMAIL PROTECTED]
> > > pache.org]
> > > > Im Auftrag von Pontus Strand
> > > > Gesendet: Montag, 17. Januar 2005 08:22
> > > > An: 'Slide Users Mailing List'
> > > > Betreff: RE: Slide search performance issues
> > > >
> > > > Ok, found the reason to why the query below didn't work, I
> > > had failed to
> > > > include a "group by"-clause.
> > > >
> > > > However, that doen't solve the problem. If I get lots of
> > > hits when doing a
> > > > search it still takes a long time to execute. What I would
> > > like to do is
> > > > to
> > > > move the limititation from the Slide server to the
> > > DB-server (where it
> > > > really belong). As I understand it the keyword "limit"
> > isn't part of
> > > > SQL-standard (Orcale for one doen't implement it) so I
> > > guess that this is
> > > > difficult do in generic terms. This is, however, important
> > > for us as we
> > > > need
> > > > the performance so which class/classes would I have to
> > > override in order
> > > > to
> > > > modify the behaviour of the search method? Is this
> > > recommended at all? Or
> > > > should we try to limit the client so we can't do to
> wide searches?
> > > >
> > > > /Pontus
> > > >
> > > > > -----Original Message-----
> > > > > From: Pontus Strand [mailto:[EMAIL PROTECTED]
> > > > > Sent: Friday, January 14, 2005 2:51 PM
> > > > > To: 'Slide Users Mailing List'
> > > > > Subject: RE: Slide search performance issues
> > > > >
> > > > >
> > > > > A quick follow-up, when working with large number of files
> > > > > the number of
> > > > > hits when doing a search could be large. As I understand it,
> > > > > it is possible
> > > > > to limit the number of responses by using the DAV:limit XML
> > > > > element from the
> > > > > DASL specification. However, the specification also states
> > > > > that the server
> > > > > may disregard the requested limit. So my questions are: Does
> > > > > Slide support
> > > > > DAV:limit? And will it work when using the
> > > > > "use-rdbms-expression-factory"
> > > > > parameter? And, finally, am I using correct syntax in the
> > > > > example below?
> > > > >
> > > > > <D:searchrequest xmlns:D =\"DAV:\">
> > > > > <D:basicsearch>
> > > > > <D:select>
> > > > > <D:allprop/>
> > > > > </D:select>
> > > > > <D:from>
> > > > > <D:scope>
> > > > > <D:href></D:href>
> > > > > </D:scope>
> > > > > </D:from>
> > > > > <D:where>
> > > > > <D:and>
> > > > > <D:eq><D:prop><D:fileextension/></D:prop>
> > > > > <D:literal>xml</D:literal></D:eq>
> > > > > </D:and>
> > > > > </D:where>
> > > > > <D:limit>
> > > > > <D:nresults>
> > > > > 10
> > > > > </D:nresults>
> > > > > </D:limit>
> > > > > </D:basicsearch>
> > > > > </D:searchrequest>
> > > > >
> > > > > The reason for my questions is that I can't get it to work
> > > > > and I can't find
> > > > > any references to this. Is there perhaps another way to limit
> > > > > the number of
> > > > > search hits?
> > > > >
> > > > > Regards,
> > > > > Pontus
> > > > >
> > > > >
> > >
> >
> ---------------------------------------------------------------------
> > > > > To unsubscribe, e-mail:
> > [EMAIL PROTECTED]
> > > > > For additional commands, e-mail:
> > > [EMAIL PROTECTED]
> > > > >
> > > >
> > > >
> > >
> >
> ---------------------------------------------------------------------
> > > > To unsubscribe, e-mail:
> [EMAIL PROTECTED]
> > > > For additional commands, e-mail:
> > [EMAIL PROTECTED]
> > >
> > >
> > >
> >
> ---------------------------------------------------------------------
> > > To unsubscribe, e-mail: [EMAIL PROTECTED]
> > > For additional commands, e-mail:
> [EMAIL PROTECTED]
> > >
> >
> >
> ---------------------------------------------------------------------
> > To unsubscribe, e-mail: [EMAIL PROTECTED]
> > For additional commands, e-mail: [EMAIL PROTECTED]
> >
>
>
>
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]