What is the correct way to obtain TraversalDescription? - spring-data-neo4j

I am using SpringRestGraphDatabase, SDN 3.1.0 and neo4j 2.1.2.
I am struggling to find the way how to obtain TraversalDescription instance.
I see that TraversalDescription traversalDescription = Traversal.description() is deprecated.
But this works!
Other way suggested elsewhere:
TraversalDescription traversalDescription = new TraversalDescriptionImpl();
does not work since TraversalDescriptionImpl is removed from neo4j 2.x
The third way suggested in neo4j user guide is through GraphDatabaseService:
TraversalDescription traversalDescription = graphDatabaseService.traversalDescription()
but then I am getting:
Caused by: java.lang.UnsupportedOperationException: Only builtin paths supported
at org.neo4j.rest.graphdb.traversal.RestTraversal.evaluator(RestTraversal.java:96)
Any ideas?
Thanks,
Milan

traversalDescription = graphDatabaseService.traversalDescription()
is indeed the correct way to obtain a TraversalDescription() in neo4j 2.x (either embedded or REST).
The problem indicated in the message you're getting is not that you're unable to obtain a TraversalDescription, and in fact it confirms that you are obtaining one, but are then trying to do an UnsupportedOperation with it.
Without seeing more of your code, I can't tell you what that is, but check out the relevant source code (github):
public RestTraversalDescription filter(Predicate<Path> pathPredicate) {
if (pathPredicate == Evaluators.all()) return add("return_filter",toMap("language","builtin", "name","all"));
if (pathPredicate == Evaluators.excludeStartPosition()) return add("return_filter",toMap("language","builtin", "name","all_but_start_node"));
throw new UnsupportedOperationException("Only builtin paths supported");
}
public RestTraversalDescription evaluator(PathEvaluator evaluator) {
if (evaluator == Evaluators.all()) return add("return_filter",toMap("language","builtin", "name","all"));
if (evaluator == Evaluators.excludeStartPosition()) return add("return_filter",toMap("language","builtin", "name","all_but_start_node"));
throw new UnsupportedOperationException("Only builtin paths supported");
}
public RestTraversalDescription evaluator(Evaluator evaluator) {
if (evaluator == Evaluators.all()) return add("return_filter",toMap("language","builtin", "name","all"));
if (evaluator == Evaluators.excludeStartPosition()) return add("return_filter",toMap("language","builtin", "name","all_but_start_node"));
throw new UnsupportedOperationException("Only builtin paths supported");
}
You'll know which of these methods specifically is throwing the exception based on the parameter you're passing in (or you could look at the line number given in the stack trace), then alter your implementation to make sure one of the if's evaluates to true so the throw doesn't get reached.

Related

Moq Verify Not Working as Expected After Upgrading to .NET Core 3.1

So as the title implies, this worked for us in .NET Core 2.2 and Moq Version 4.10.1. After upgrading to .NET Core 3.1 and Moq Version 4.14.5, the verify method is failing saying the method specified hasn't been called (no changes to the underlying code). I rolled back Moq to version 4.10.1 just to see if it was due to a change within the new version of Moq. I still get the same error.
Trying to verify that a log message has been written to the ILogger.
Weird thing is, if I debug the unit test and look at the mocked object with a variable watch, it shows that the method has indeed been invoked.
Relevant code:
public class AuditFilter, IResultFilter
{
...
public void OnResultExecuted( ResultExecutedContext context )
{
if( !IsContextValid( context ) )
{ return; }
...
}
public override bool IsContextValid( FilterContext context )
{
if( context == null )
{
Logger.Error( "Error writing to the audit log", new ArgumentNullException( nameof( context ) ) );
return false;
}
if( context.HttpContext == null )
{
Logger.LogError( "Error writing to the audit log", new ArgumentNullException( nameof( context.HttpContext ) ) );
return false;
}
return true;
}
public ILogger Logger { get; set; }
...
}
public class AuditTests : BaseTests
{
...
private Mock<ILogger> _mockLog;
private AuditFilter _filter;
[SetUp]
public void Setup()
{
_mockLog = new Mock<Microsoft.Extensions.Logging.ILogger>();
_mockLog.SetupAllProperties;
_filter = new AuditFilter();
}
[Test]
public void Service_Filters_Audit_IsContextValid_Context_Null()
{
var expected = false;
_filter.Logger = _mockLog.Object;
var actual = _filter.IsContextValid( null );
_mockLog.Verify( logger => logger.Log( LogLevel.Error,
It.IsAny<EventId>(),
It.IsAny<object>(),
It.IsAny<ArgumentNullException>(),
It.IsAny<Func<object, Exception, string>>() ),
Times.Once );
Assert.AreEqual( expected, actual );
}
...
}
Note: The method ILogger.LogError is a Microsoft extension method for ILogger that calls ILogger.Log method.
Below is the exception that is thrown.
Note: An integer implicitly casts to Microsoft.Extensions.Logging.EventId, the second input parameter type for the ILogger.Log method.
These signatures appear to match to me; so I'm not sure why it's saying it wasn't invoked.
To reiterate, this code worked prior to upgrading to .NET Core 3.1 and still works in our pre-forked code.
Also, before someone suggests that the method needs to be setup: it worked before the upgrade without it, and I already tried it and it didn't work.
I believe the problem will be this part of the verify expression
It.IsAny<Func<object, Exception, string>>()
Under the covers it's not a Func<object, Exception, string> and the mock IsAny matcher doesn't match because of this difference. If you modify it to
(Func<object, Exception, string>) It.IsAny<object>()
it should match. Below is what I've settled on as the starting point for verify expressions as it works for at least .NET Core 2.* onwards:
loggerMock.Verify(x => x.Log(
It.IsAny<LogLevel>(),
It.IsAny<EventId>(),
It.IsAny<IReadOnlyList<KeyValuePair<string, object>>>(),
It.IsAny<Exception>(),
(Func<object, Exception, string>) It.IsAny<object>()),
Times.Exactly(expectedNumberOfInvocations));
You can use It.IsAny<object>() for the third parameter but I find this is more convenient when interrogating the properties.
I've been doing a fair bit of log invocation verification at work recently for black box processes so now I mostly use Moq.Contrib.ExpressionBuilders.Logging to build fluent, readable verify expressions. Disclaimer: I am the author.
Like I had added in the comments, this is a known issue with Moq and .NET Core right from the Preview version of .NET Core 3.0. Please take a look at the github issue to understand why this broke with the update.
In a nutshell, from the issue linked, the failure here is caused due to fact that the type being passed to Logger.Log method is now changed to FormattedLogValues. Though there is a generic type matcher It.IsAnyType introduced in Moq 4.13.0, that would not address the issue.
The reason for this, as one of the authors of Moq states here
The important bit (for now) is that It.IsAnyType is not used in a nested position in the It.IsAny<> type argument.
As a workaround we should replace
It.IsAny<Func<object, Exception, string>>()
with
(Func<object, Exception, string>)It.IsAny<object>()
The rationale provided for this, is to improve the performance of the type matcher as the former would result in the decomposition of all the type parameters underneath the hood to see if there is a type matcher included in the first place.

Eclipse CDT: Problems with extension point CIndexer

Problem 1: I can't find org.eclipse.cdt.core.index.IIndexer
From the API:
API Information: Plug-ins that want to extend this extension point must implement org.eclipse.cdt.core.index.IIndexer interface.
Is the API Information incorrect/deprecated? Which interface should be implemented if not IIndexer?
Problem 2: I can install my own Indexer in CDT version 6.8 (eclipse 2019-06) but not in version 6.5 (eclipse 2018-09), though I don't see the difference in the plugin code.
More Details:
My Indexer class:
#SuppressWarnings("restriction")
public class MyIndexer extends PDOMFastIndexer {
public static final String ID = "de.blub.MyIndexer";
#Override
public String getID() {
return ID;
}
#Override
public IPDOMIndexerTask createTask(ITranslationUnit[] added, ITranslationUnit[] changed,
ITranslationUnit[] removed) {
if (...) {
return new MyIndexerTask(added, changed, removed, this, true);
} else {
return super.createTask(added, changed, removed);
}
}
The plugin.xml
<extension
id="org.eclipse.cdt.core.fastIndexer"
name="My Indexer"
point="org.eclipse.cdt.core.CIndexer">
<run
class="de.blub.MyIndexer">
</run>
The MANIFEST.MF File lists org.eclipse.cdt.core in the Require-Bundle section without bundle-version. Of course the cdt plugin has different versions:
In Eclipse 2019-06:
Eclipse CDT C/C++ Development Tools Core 6.8.1.201907021957 org.eclipse.cdt.core
In Eclipse 2018-09:
Eclipse CDT C/C++ Development Tools Core 6.5.0.201811180605 org.eclipse.cdt.core
This code is from org.eclipse.cdt.internal.core.pdom.PDOMManager:
private IPDOMIndexer newIndexer(String indexerId, Properties props) throws CoreException {
IPDOMIndexer indexer = null;
// Look up in extension point
IExtension indexerExt = Platform.getExtensionRegistry().getExtension(CCorePlugin.INDEXER_UNIQ_ID, indexerId);
if (indexerExt != null) {
IConfigurationElement[] elements = indexerExt.getConfigurationElements();
for (IConfigurationElement element : elements) {
if ("run".equals(element.getName())) { //$NON-NLS-1$
try {
indexer = (IPDOMIndexer) element.createExecutableExtension("class"); //$NON-NLS-1$
indexer.setProperties(props);
} catch (CoreException e) {
CCorePlugin.log(e);
}
break;
}
}
}
// Unknown index, default to the null one
if (indexer == null)
indexer = new PDOMNullIndexer();
return indexer;
}
The code is the same for both cdt versions. indexer becomes a PDOMFastIndexer in eclipse 2018-09, but a MyIndexer in 2019-06.
One difference I could see is that in RegistryObjectManager
private Object basicGetObject(int id, byte type) {
Object result = cache.get(id);
if (result != null)
return result;
...
}
An id is used to get the correct ConfigurationElement (result) from a cache object, which I don't really understand how it is built up. However, the returned ConfigurationElement contains a field propertiesAnsValues which is incorrect in the one case (org.eclipse.cdt.internal.core.pdom.indexer.PDOMFastIndexer instead of de.blub.MyIndexer).
How can I fix that to have my own indexer in eclipse 2018-09, too?
Please also note my Problem 1. Because if the API description is correct, it means I'm trying to install my indexer the wrong way and need to do something to 'see' the IIndexer interface.
According to the schema definition, the class you need to derive from is IPDOMIndexer (which you're already doing). You can also tell this from the PDOMManager code you quoted, which casts the result of createExecutableExtension() to IPDOMIndexer.
(The comment saying to use org.eclipse.cdt.core.index.IIndexer is indeed out of date. Based on a brief look, that interface hasn't existed since at least 2005. Patches to update the extension point documentation are welcome.)
As for your second problem, I believe it's because you're using id="org.eclipse.cdt.core.fastIndexer" for your extension, which is already in use by one of CDT's built-in indexers. The id needs to identify your extension uniquely (so you can make it something like myproject.MyIndexer.)

Sitecore IsPageEditor and IsExperienceEditor

We are currently writing a module for Sitecore and have ran into a problem.
We have a pipeline in which we do the following check:
if (Sitecore.Context.PageMode.IsExperienceEditor)
{
return;
}
The problem is that one of our clients are running and older version of Sitecore (8.0 update 5) where the property IsExperienceEditor does not exist yet. See Sitecore release notes for next update where it is introduced.
To quickly fix the error we used the older deprecated property which is this:
if (Sitecore.Context.PageMode.IsPageEditor)
{
return;
}
Now the question is, is there any way in which we can test for the Sitecore version so we can have backwards compatibility in the module?
You can use the code which is executed in Sitecore in background of both properties mentioned by you:
if (Sitecore.Context.Site.DisplayMode == Sitecore.Sites.DisplayMode.Edit)
{
return;
}
I know that using Sitecore.Context.PageMode.IsExperienceEditor (or Sitecore.Context.PageMode.IsPageEditor) is more elegant, but in a situation when you need to support both old and new Sitecore versions, that's sounds like a good option.
The deprecated property of IsPageEditor is still present specifically for the purpose of backward compatibility. IsExperienceEditor is just a renamed property that does the same thing that IsPageEditor does.
However you can check for the existence of a property like this:
public static bool HasProperty(this object obj, string propertyName)
{
return obj.GetType().GetProperty(propertyName) != null;
}
Another option is to make two different versions of the module, if the implementation becomes significantly different for the different versions of Sitecore.

How can I ignore some error in Xcode?

I am a new in using clang/Xcode. I have a question now that I build a code analyzer through clang-rewriter and I must get a log from return statement of every function , so I do this.
#define return if(fun1(),1) return
But when I come across this situation , the clang cannot make me compile success
As I have to build the prj automatically , I want to find a way to ignore this error, like g++ ,I can through '-Wno-return-type' to ignore this warning, but I configure this in Xcode,it is not used. :(sad
IMO the problem is not the warning but the way you return from the block. Instead of adding an explicit else branch you can just write the following (which is semantically the same):
if(cmp != NSOrderedSame) {
return cmp;
}
return [lhs.tagName compare:rhs.tagName];

CRecordset::snapshot doesn't work in VS2012 anymore - what's the alternative?

Apparently, in VS2012, SQL_CUR_USE_ODBC is deprecated. [Update: it appears that the cursors library has been removed from VS2012 entirely].
MFC's CDatabase doesn't use it anymore (whereas it was the default for VS2010 and earlier versions of MFC), but instead uses SQL_CUR_USE_DRIVER.
Unfortunately, SQL_CUR_USE_DRIVER doesn't work properly with the Jet ODBC driver (we're interacting with an Access database). The driver initially claims to support positional operations (but not positional updates), but when an attempt is made to actually query the database, all concurrency models fail until the MFC library drops down to read-only interaction with the database (which is not going to fly for us).
Questions
Is this MS's latest attempt to force devs to move away from Jet based datasources and migrate to SQL Express (or the like)?
Is there another modality that we should be using to interact with our Access databases through VS 2012 versions of MFC/ODBC?(1)
See also:
http://social.msdn.microsoft.com/Forums/kk/vcmfcatl/thread/acd84294-c2b5-4016-b4d9-8953f337f30c
Update: Looking at the various options, it seems that the cursor library has been removed from VS2012's ODBC library. Combined with the fact that Jet doesn't correctly support positional updates(2), it makes "snapshot" mode unusable. It does appear to support "dynaset" as long as the underlying tables have a primary key. Unkeyed tables are incompatible with "dynaset" mode(3). So - I can stick with VS 2010, or I can change my tables to include an autonumber or something similar in order to ensure a pkey is available so I can use dynaset mode for the recordsets.
(1) e.g. should we be using a different open type for CRecordset? We currently use CRecordset::snapshot. But I've never really understood the various modes snapshot, dynamic, dynaset. A quick set of "try each" has failed to get a working updatable interface to our access database...
(2) it claims to when queried initially, but then returns errors for all concurrency modes that it previously claimed to support
(3) "dynamic" is also out, since Jet doesn't support it at all (from what I can tell from my tests).
I found a solution that appears to work. I overrode OpenEx the exact same way VS 2012 has it because we need that to call the child version of AllocConnect since it is not virtual in the parent. I also overrode AllocConnect as mentioned. In the derived version of CDatabase, try the following code:
MyCDatabase.h
BOOL OpenEx(LPCTSTR lpszConnectString, DWORD dwOptions = 0);
void AllocConnect(DWORD dwOptions);
MyCDatabase.cpp
BOOL MyCDatabase::OpenEx(LPCTSTR lpszConnectString, DWORD dwOptions)
{
ENSURE_VALID(this);
ENSURE_ARG(lpszConnectString == NULL || AfxIsValidString(lpszConnectString));
ENSURE_ARG(!(dwOptions & noOdbcDialog && dwOptions & forceOdbcDialog));
// Exclusive access not supported.
ASSERT(!(dwOptions & openExclusive));
m_bUpdatable = !(dwOptions & openReadOnly);
TRY
{
m_strConnect = lpszConnectString;
DATA_BLOB connectBlob;
connectBlob.pbData = (BYTE *)(LPCTSTR)m_strConnect;
connectBlob.cbData = (DWORD)(AtlStrLen(m_strConnect) + 1) * sizeof(TCHAR);
if (CryptProtectData(&connectBlob, NULL, NULL, NULL, NULL, 0, &m_blobConnect))
{
SecureZeroMemory((BYTE *)(LPCTSTR)m_strConnect, m_strConnect.GetLength() * sizeof(TCHAR));
m_strConnect.Empty();
}
// Allocate the HDBC and make connection
AllocConnect(dwOptions);
if(!CDatabase::Connect(dwOptions))
return FALSE;
// Verify support for required functionality and cache info
VerifyConnect();
GetConnectInfo();
}
CATCH_ALL(e)
{
Free();
THROW_LAST();
}
END_CATCH_ALL
return TRUE;
}
void MyCDatabase::AllocConnect(DWORD dwOptions)
{
CDatabase::AllocConnect(dwOptions);
dwOptions = dwOptions | CDatabase::useCursorLib;
// Turn on cursor lib support
if (dwOptions & useCursorLib)
{
::SQLSetConnectAttr(m_hdbc, SQL_ATTR_ODBC_CURSORS, (SQLPOINTER)SQL_CUR_USE_ODBC, 0);
// With cursor library added records immediately in result set
m_bIncRecordCountOnAdd = TRUE;
}
}
Please note that you do not want to pass in useCursorLab to OpenEx at first, you need to override it in the hacked version of AllocConnect.
Also note that this is just a hack but it appears to work. Please test all your code to be sure it works as expected but so far it works OK for me.
If anyone else runs into this issue, here's what seems to be the answer:
For ODBC to an Access database, connect using CDatabase mydb; mydb.OpenEx(.., 0), so that you ask the system not to load the cursor library.
Then for the recordsets, use dynaset CMyRecordset myrs; myrs.Open(CRecordset::dynaset, ...).
Finally, you must make sure that your tables have a primary key in order to use dynasets (keysets).
Derive CDatabase and override OpenEx. In your derived class CMyDatabase, replace the call to AllocConnect to MyAllocConnect. Obviously, your MyAllocConnect function should call SQLSetConnectOption with the desired parameter:
// Turn on cursor lib support
if (dwOptions & useCursorLib)
{
AFX_SQL_SYNC(::SQLSetConnectOption(m_hdbc, SQL_ODBC_CURSORS, SQL_CUR_USE_ODBC));
// With cursor library added records immediately in result set
m_bIncRecordCountOnAdd = TRUE;
}
Then use your CMyDatabase class instead of CDatabase for all your queries.