blob: f4abb892321ab976f03d895fd0359681ddd4db42 [file] [log] [blame]
/*=========================================================================
* Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
* This product is protected by U.S. and international copyright
* and intellectual property laws. Pivotal products are covered by
* one or more patents listed at http://www.pivotal.io/patents.
*=========================================================================
*/
package com.gemstone.gemfire.cache.client.internal;
import java.util.ArrayList;
import com.gemstone.gemfire.CancelCriterion;
import com.gemstone.gemfire.cache.CacheClosedException;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.RegionService;
import com.gemstone.gemfire.cache.client.ClientCache;
import com.gemstone.gemfire.cache.query.QueryService;
import com.gemstone.gemfire.cache.query.internal.ProxyQueryService;
import com.gemstone.gemfire.distributed.internal.ServerLocation;
import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
import com.gemstone.gemfire.internal.cache.LocalRegion;
import com.gemstone.gemfire.pdx.PdxInstance;
import com.gemstone.gemfire.pdx.PdxInstanceFactory;
import com.gemstone.gemfire.pdx.internal.PdxInstanceFactoryImpl;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
/**
* A wrapper class over an actual Cache instance. This is used when the
* multiuser-authentication attribute is set to true. Application must use
* its {@link #getRegion(String)} API instead that of actual Cache instance for
* getting a reference to Region instances, to perform operations on server.
*
* TODO Avoid creating multiple instances of ProxyCache for a single user.
*
* @see ClientCache#createAuthenticatedView(Properties)
* @see ProxyQueryService
* @see ProxyRegion
* @since 6.5
*/
public class ProxyCache implements RegionService {
private final GemFireCacheImpl cache;
private UserAttributes userAttributes;
private ProxyQueryService proxyQueryService;
private boolean isClosed = false;
private final Stopper stopper = new Stopper();
public ProxyCache(Properties properties, GemFireCacheImpl cache, PoolImpl pool) {
this.userAttributes = new UserAttributes(properties, pool);
this.cache = cache;
}
public void close() {
close(false);
}
public void close(boolean keepAlive) {
if (this.isClosed) {
return;
}
// It should go to all the servers it has authenticated itself on and ask
// them to clean-up its entry from their auth-data structures.
try {
if (this.proxyQueryService != null) {
this.proxyQueryService.closeCqs(keepAlive);
}
UserAttributes.userAttributes.set(this.userAttributes);
Iterator<ServerLocation> iter = this.userAttributes.getServerToId()
.keySet().iterator();
while (iter.hasNext()) {
ProxyCacheCloseOp.executeOn(iter.next(), (PoolImpl)this.userAttributes.getPool(),
this.userAttributes.getCredentials(), keepAlive);
}
ArrayList<ProxyCache> proxyCache = ((PoolImpl)this.userAttributes.getPool()).getProxyCacheList();
synchronized (proxyCache) {
proxyCache.remove(this);
}
} finally {
// @todo I think some NPE will be caused by this code.
// It would be safer to not null things out.
// It is really bad that we null out and then set isClosed true.
this.isClosed = true;
this.proxyQueryService = null;
this.userAttributes.setCredentials(null);
this.userAttributes = null;
UserAttributes.userAttributes.set(null);
}
}
// TODO remove this method
public String getName() {
return this.cache.getName();
}
public QueryService getQueryService() {
preOp();
if (this.proxyQueryService == null) {
this.proxyQueryService = new ProxyQueryService(this, userAttributes
.getPool().getQueryService());
}
return this.proxyQueryService;
}
public <K, V> Region<K, V> getRegion(String path) {
preOp();
// TODO Auto-generated method stub
// ProxyRegion region = this.proxyRegionList.get(path);
// if (region != null) {
// return region;
// }
// else {
if (this.cache.getRegion(path) == null) {
return null;
} else {
if (!this.cache.getRegion(path).getAttributes().getDataPolicy().isEmpty()) {
throw new IllegalStateException(
"Region's data-policy must be EMPTY when multiuser-authentication is true");
}
return new ProxyRegion(this, this.cache.getRegion(path));
}
// }
}
public boolean isClosed() {
return this.isClosed;
}
public void setProperties(Properties properties) {
preOp();
this.userAttributes.setCredentials(properties);
}
public Properties getProperties() {
preOp();
return this.userAttributes.getCredentials();
}
public void setUserAttributes(UserAttributes userAttributes) {
preOp();
this.userAttributes = userAttributes;
}
public UserAttributes getUserAttributes() {
preOp();
return this.userAttributes;
}
public Object getUserId(Object key) {
preOp();
if (!(key instanceof ServerLocation)) {
throw new IllegalArgumentException(
"Key must be of type ServerLocation, but is " + key.getClass());
}
return this.userAttributes.getServerToId().get(key);
}
private void preOp() {
this.stopper.checkCancelInProgress(null);
}
protected class Stopper extends CancelCriterion {
/* (non-Javadoc)
* @see com.gemstone.gemfire.CancelCriterion#cancelInProgress()
*/
@Override
public String cancelInProgress() {
String reason = cache.getCancelCriterion().cancelInProgress();
if (reason != null) {
return reason;
}
if (isClosed()) {
return "Authenticated cache view is closed for this user.";
}
return null;
}
/* (non-Javadoc)
* @see com.gemstone.gemfire.CancelCriterion#generateCancelledException(java.lang.Throwable)
*/
@Override
public RuntimeException generateCancelledException(Throwable e) {
String reason = cancelInProgress();
if (reason == null) {
return null;
}
RuntimeException result = cache.getCancelCriterion().generateCancelledException(e);
if (result != null) {
return result;
}
if (e == null) {
// Caller did not specify any root cause, so just use our own.
return new CacheClosedException(reason);
}
try {
return new CacheClosedException(reason, e);
}
catch (IllegalStateException e2) {
// Bug 39496 (Jrockit related) Give up. The following
// error is not entirely sane but gives the correct general picture.
return new CacheClosedException(reason);
}
}
}
public CancelCriterion getCancelCriterion() {
return this.stopper;
}
/* (non-Javadoc)
* @see com.gemstone.gemfire.cache.RegionService#rootRegions()
*/
public Set<Region<?, ?>> rootRegions() {
preOp();
Set<Region<?, ?>> rRegions = new HashSet<Region<?,?>>();
Iterator<LocalRegion> it = this.cache.rootRegions().iterator();
while (it.hasNext()) {
LocalRegion lr = it.next();
if (!lr.getAttributes().getDataPolicy().withStorage()) {
rRegions.add(new ProxyRegion(this, lr));
}
}
return Collections.unmodifiableSet(rRegions);
}
public PdxInstanceFactory createPdxInstanceFactory(String className) {
return PdxInstanceFactoryImpl.newCreator(className, true);
}
public PdxInstanceFactory createPdxInstanceFactory(String className, boolean b) {
return PdxInstanceFactoryImpl.newCreator(className, b);
}
public PdxInstance createPdxEnum(String className, String enumName, int enumOrdinal) {
return PdxInstanceFactoryImpl.createPdxEnum(className, enumName, enumOrdinal, this.cache);
}
}