Tuesday, 24 February 2015

Returning custom error JSON in a Web API

Often when a Web API fails you want to return more than a HTTP status code and a string. Like a full JSON object. Yet you don't want to corrupt your original return type for normal flow.
These articles describe how you can return a different type for error scenarios:

http://blog.codeishard.net/2013/02/09/webapi-and-the-behavior-of-exceptions-and-an-alternative-configurable-way-to-deal/

http://stackoverflow.com/questions/16243021/return-custom-error-objects-in-web-api

Monday, 23 February 2015

Creating GUIDs (UUIDs) in Javascript

With the advance of distributed systems, there is a growing need to generate unique identifiers on the client.

There are several versions of GUID algorithms. .NET ultimately wraps the CoCreateGuid function. Windows originally started with an algorithm using the machine's MAC address, but now it uses version 4 UUIDs. You can tell this because they have the form:

xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx

Although the chance of a conflict is remote in the extreme, it is good practice to use the same version scheme on both client on server. Broofa creates RFC-compliant GUIDs (both version 1 and version 4) in JavaScript. Use version 4 for uniformity with Server-side Windows.

Saturday, 21 February 2015

Minecraft Forge 1.7.2 stopped working

Minecraft Forge 1.7.2 stopped working with a new Java update. Fortunately this post details how to fix it.

I quote:

"
So you may have heard that as of Java 8 update 20, a bug came to light in Forge which causes a crash at startup. This appears to affect both Minecraft 1.6 and 1.7. Fortunately, later versions of Forge for 1.7.10 correct the issue. But 1.6.4 and 1.7.2 are still affected, as are many versions for 1.7.10 still in use. You could easily just use Java 7, or Java 8 update 11, and not be affected by this bug. But for future-proofing sake, in case someone wants to run Java 8 but a security issue is discovered at some point in the future which makes update 11 not very safe, I decided to just fix Forge.

Only one file is the problem, so that's all you need:

CoreModManager.class, for Forge #965 for Minecraft 1.6.4.
or
CoreModManager.class, for Forge #1121 / #1147 for Minecraft 1.7.2
or
CoreModManager.class, for Forge #1208 for Minecraft 1.7.10

-- Vanilla --

I'm going to assume you already have Forge installed into the vanilla launcher for these instructions.

From here you need to find your way into your libraries directory for Forge. On Windows, the direct route would be:

For 1.6.4: %appdata%\.minecraft\libraries\net\minecraftforge\minecraftforge\9.11.1.965

For 1.7.2: %appdata%\.minecraft\libraries\net\minecraftforge\forge\1.7.2-10.12.2.1147 (or switch 1147 for the version you're using)

For 1.7.10: %appdata%\.minecraft\libraries\net\minecraftforge\forge\1.7.10-10.13.0.1208

If you use Linux then you know your way around your home directory. And if you use OSX, then I'm sure someone else can help you find it, but I imagine that your base Minecraft directory is in your home directory somewhere as well like Linux.

You can make a backup of the JAR if you want at this point. But now open up the JAR in WinRAR or what ever program you use for such things. First, go ahead and delete the META-INF directory in the root of the JAR, or you'll get a crash related to security, just like in the old JAR-modding days. Now navigate your way through cpw/mods/fml/relauncher. You should see a CoreModManager.class in here. Just drop this patched version on top, and you should be good to go!


-- FTB --

This is relatively identical to the above instructions. The only difference is that you have to find the libraries directory inside your FTB directory instead. Then do the same process as above, and this should fix every related pack on the launcher.

-- Technic --

This is a bit different. You need to patch individual modpacks. And every time a pack is updated, you'll probably have to patch it again. But it's not a big deal. For this, first go into your packs directory. For Windows this is: %appdata%\.technic\modpacks

Now go into whichever pack you want to fix. For this example we'll use the main Tekkit. So navigate into tekkitmain, then into bin. You should see a modpack.jar here. This is basically your Forge JAR. Follow the process of above for patching the JAR, of deleting META-INF and adding the class file into the appropriate place, and your pack should now run again.

-- ATLauncher --

Again, this is slightly different, requiring you to fix per-instance like Technic. Go to your ATLauncher directory, then into instances. Find the instance you want to repair, then go into jarmods. You should see the Forge JAR here. So do the above mentioned process to patch the JAR, and the pack should be fixed. Like Technic, updates might break it.

-- MultiMC -- 

I have no easy fix for this at this time, because it automatically redownloads the Forge JAR after it detects modification, which is both nice and annoying depending on the situation!


-- Servers --

In this case, Forge will already be in the server JAR. You won't want to erase all of META-INF or the server won't launch, just deleting FORGE.DSA is enough according to DAOWAce's post below. Then just copy the class file you downloaded into the appropriate place in the JAR.



-- Misc --

Now for the technical details of what this does, for those interested. Java 8 update 20 changed the way Collections.sort works, no longer cloning a List but modifying it in-place. Since FML is iterating this list at this particular moment, you get the crash. So what this patch does is replace Collections.sort with a wrapper function inside CoreModManager.

It does this:

public static <T> void sort(List<T> list, Comparator<? super T> c)
{
T[] toSort = list.toArray((T[])new Object[list.size()]);
Arrays.sort(toSort, c);
for (int j = 0; j < toSort.length; j++) list.set(j, toSort[j]);


This is basically a modified version of the same code used to fix later versions of FML, just implemented differently for the sake of a patch.

What I did was compile this bit of code in an otherwise empty class, then used Java Bytecode Editor to extract the bytecode from that class and create the identical method in CoreModManager. Lastly I modified the sortTweakList method to invoke cpw/mods/fml/relauncher/CoreModManager/sort instead of java/util/Collections/sort. You can use JBE to confirm youself that that's the only difference between this patched file and the original if you're concerned at all.

There's a chance that the 1.6.4 patch will work on other versions of Forge for 1.6.x, you would just have to try it and see. The two 1.7.2 builds are the 'latest' and 'recommended' ones, and both had an identical version of CoreModManager, though it might work on earlier builds for that version as well if necessary.

Hope this helps!
"

Friday, 6 February 2015

SQL for showing outstanding replication commands

The collection of T-SQL below helps identify outstanding replication commands
use distribution
go
select * from dbo.MSarticles
where article_id IN (SELECT Article_id from MSrepl_commands
where xact_seqno = 0x0002E17600000131000600000000)

sp_browsereplcmds @xact_seqno_end = '0x0002E17600000131000600000000'
sp_browsereplcmds @xact_seqno_start = '0x0002E17600000131000600000000', @xact_seqno_end = '0x0002E17600000131000600000000', @Command_id = 1, @publisher_database_id = 1

select * FROM MSArticles a where article in ('DiscountCode', 'DiscountCodeCountry', 'DiscountRule')
select * from M

-- Discount Code
sp_browsereplcmds @article_id = 60, @xact_seqno_end = '0x0002E17600000131000600000000'
sp_browsereplcmds @article_id = 61, @xact_seqno_end = '0x0002E17600000131000600000000'
sp_browsereplcmds @article_id = 62, @xact_seqno_end = '0x0002E17600000131000600000000'

EXECUTE sp_replmonitorsubscriptionpendingcmds 
@publisher ='.\PublisherDb', -- Put publisher server name here
@publisher_db = 'MyPubDb', -- Put publisher database name here
@publication ='Discount-Publication',  -- Put publication name here
@subscriber ='.\SubscriberDb', -- Put subscriber server name here
@subscriber_db ='MySubDb', -- Put subscriber database name here
@subscription_type ='0' -- 0 = push and 1 = pull
The SQL below shows the replication performance for a table.

use distribution
go

select min(dh.delivery_latency) min, avg(dh.delivery_latency) avg, MAX(dh.delivery_latency) max
from MSarticles a 
inner join MSpublications (nolock) p on a.publication_id = p.publication_id
inner join MSsubscriptions (nolock) s ON p.publication_id = s.publication_id and s.article_id = a.article_id
inner join master..sysservers (nolock) ss ON s.subscriber_id = ss.srvid 
inner join master..sysservers (nolock) srv ON srv.srvid = p.publisher_id 
inner join MSdistribution_agents (nolock) da ON da.publisher_id = p.publisher_id  AND da.subscriber_id = s.subscriber_id and da.publication = p.publication
inner join distribution.dbo.MSdistribution_history (nolock) dh on dh.agent_id = da.id
where a.destination_object = 'MyTable'
and s.subscriber_db = 'MyDB'

Find out the replication properties of a table

The script below lists the publisher, subscriber and publication for a replicated table in SQL Server. It is executed against the distribution database.

use distribution
go

-- View the replication properties of a table
select a.publisher_db, s.subscriber_db, a.article, p.publication, p.publication_type
from MSarticles a 
inner join MSpublications p on a.publication_id = p.publication_id
inner join MSsubscriptions s ON p.publication_id = s.publication_id and s.article_id = a.article_id
inner join master..sysservers ss ON s.subscriber_id = ss.srvid 
inner join master..sysservers srv ON srv.srvid = p.publisher_id 
inner join MSdistribution_agents da ON da.publisher_id = p.publisher_id  AND da.subscriber_id = s.subscriber_id and da.publication = p.publication
where a.destination_object like '%discountusage%'

Testing a REST API with Powershell

With the following Powershell script, you can issue a POST request to a REST endpoint

add-type @"
    using System.Net;
    using System.Security.Cryptography.X509Certificates;
    public class TrustAllCertsPolicy : ICertificatePolicy {
        public bool CheckValidationResult(
            ServicePoint srvPoint, X509Certificate certificate,
            WebRequest request, int certificateProblem) {
            return true;
        }
    }
"@

[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy

$uri = 'https://myurl.com/v1/MyResource?param=true'

$body = 
'{
    "products": [
        {
            "productId": 1,
            "quantity": 0
        },
        {
            "productId": 2,
            "quantity": 0
        }
    ]
}'


$response = Invoke-WebRequest -Uri $uri -Method POST -Body $body -ContentType 'application/json; charset=utf-8' 
$response.Headers