Checking in vendor folder for ease of using go get.

This commit is contained in:
Renan DelValle 2018-10-23 23:32:59 -07:00
parent 7a1251853b
commit cdb4b5a1d0
No known key found for this signature in database
GPG key ID: C240AD6D6F443EC9
3554 changed files with 1270116 additions and 0 deletions

View file

@ -0,0 +1,33 @@
<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.
-->
<configuration>
<configSections>
<section name="rebus" type="Rebus.Configuration.RebusConfigurationSection, Rebus"/>
</configSections>
<rebus inputQueue="MyResponses" errorQueue="MyErrors" workers="1">
<endpoints>
<add messages="RebusSample.MathRequestCall, RebusSample" endpoint="MathRequests"/>
<add messages="RebusSample.MathResponseCall, RebusSample" endpoint="MathResponses"/>
</endpoints>
</rebus>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>

View file

@ -0,0 +1,81 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
using Rebus.Configuration;
using Rebus.RabbitMQ;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RebusSample.Client;
using RebusSample.Server;
namespace RebusSample
{
class Program
{
static BuiltinContainerAdapter StartRequestServer(string server)
{
// client Rebus configuration
var adapter = new BuiltinContainerAdapter();
Configure.With(adapter)
.Transport(t => t.UseRabbitMq("amqp://" + server, "MathRequests", "MathRequestErrors"))
.MessageOwnership(o => o.FromRebusConfigurationSection())
.CreateBus().Start();
// register all relevant message handlers
adapter.Register(typeof(MathRequestCallHandler));
return adapter;
}
static BuiltinContainerAdapter StartResponseServer(string server)
{
// client Rebus configuration
var adapter = new BuiltinContainerAdapter();
Configure.With(adapter)
.Transport(t => t.UseRabbitMq("amqp://" + server, "MathResponses", "MathResponseErrors"))
.MessageOwnership(o => o.FromRebusConfigurationSection())
.CreateBus().Start();
// register all relevant message handlers
adapter.Register(typeof(MathResponseCallHandler));
return adapter;
}
static void Main(string[] args)
{
string server = "localhost";
// start all servers
var req = StartRequestServer(server);
var rsp = StartResponseServer(server);
// send the first message
var random = new Random();
var client = new MathRequestClient(server);
client.DoTheMath(random.Next(), random.Next());
// now what?
Console.Write("Hit <ENTER> to stop ... ");
Console.ReadLine();
}
}
}

View file

@ -0,0 +1,38 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("RebusSample")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("RebusSample")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: Guid("0af10984-40d3-453d-b1e5-421529e8c7e2")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View file

@ -0,0 +1,21 @@
Sample code for the combination of Thrift with Rebus.
Rebus is a .NET service bus, similar to NServiceBus, but more lightweight.
It ihas been mainly written by Mogens Heller Grabe and is currently hosted
on GitHub (https://github.com/rebus-org/Rebus)
As with all ServiceBus or MQ scenarios, due to the highly asynchronous
operations it is recommended to do all calls as "oneway void" calls.
The configuration can be done via App.Config, via code or even mixed from
both locations. Refer to the Rebus documentation for further details. For
this example, since we are effectively implementing two queue listeners in
only one single process, we do configuration of incoming and error queues
in the code.
If you want to communicate with non-NET languages, you may need a customized
serializer as well, in order to override Rebus' default wire format. Please
refer to the Rebus docs on how to do that (it's not that hard, really).
Additional requirements:
- RabbitMQ .NET client (see nuget)

View file

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.
-->
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{264E2126-EDE0-4B47-89C1-B397B25BB13D}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>RebusSample</RootNamespace>
<AssemblyName>RebusSample</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="RabbitMQ.Client">
<HintPath>..\..\..\..\..\Toolbox\ServiceBus\3rdparty\rabbitmq-dotnet-client-3.2.1-dotnet-3.0\bin\RabbitMQ.Client.dll</HintPath>
</Reference>
<Reference Include="Rebus">
<HintPath>..\..\..\..\..\Toolbox\ServiceBus\3rdparty\Rebus-master\deploy\NET40\Rebus.dll</HintPath>
</Reference>
<Reference Include="Rebus.RabbitMQ">
<HintPath>..\..\..\..\..\Toolbox\ServiceBus\3rdparty\Rebus-master\deploy\NET40\Rebus.RabbitMQ.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="gen-csharp\BasicMathClient.cs" />
<Compile Include="gen-csharp\BasicMathServer.cs" />
<Compile Include="ServiceImpl\Both.cs" />
<Compile Include="ServiceImpl\Client.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ServiceImpl\Server.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<ProjectReference Include="..\..\lib\csharp\src\Thrift.csproj">
<Project>{499eb63c-d74c-47e8-ae48-a2fc94538e9d}</Project>
<Name>Thrift</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>cd $(ProjectDir)
if not exist gen-csharp\*.cs thrift -gen csharp sample.thrift
</PreBuildEvent>
</PropertyGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View file

@ -0,0 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.30110.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RebusSample", "RebusSample.csproj", "{264E2126-EDE0-4B47-89C1-B397B25BB13D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thrift", "..\..\lib\csharp\src\Thrift.csproj", "{499EB63C-D74C-47E8-AE48-A2FC94538E9D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{264E2126-EDE0-4B47-89C1-B397B25BB13D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{264E2126-EDE0-4B47-89C1-B397B25BB13D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{264E2126-EDE0-4B47-89C1-B397B25BB13D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{264E2126-EDE0-4B47-89C1-B397B25BB13D}.Release|Any CPU.Build.0 = Release|Any CPU
{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,35 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
using System;
namespace RebusSample
{
// generic data container for serialized Thrift calls
public class GenericThriftServiceCall
{
public byte[] rawBytes;
}
// specific containers (one per Thrift service) to leverage Rebus' handler routing
public class MathRequestCall : GenericThriftServiceCall { }
public class MathResponseCall : GenericThriftServiceCall { }
}

View file

@ -0,0 +1,157 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
using Rebus;
using Rebus.Configuration;
using Rebus.Messages;
using Rebus.RabbitMQ;
using System;
using System.Collections.Generic;
using System.IO;
using Thrift.Protocol;
using Thrift.Transport;
/*
* The client emits calls to BasicMathServers
*
* The client implements the BasicMathClient service.
* If the server has processed our request, we get the results back through this service
*/
namespace RebusSample.Client
{
// handler to be registered with Rebus
class MathResponseCallHandler : IHandleMessages<MathResponseCall>
{
public void Handle(MathResponseCall message)
{
// Thrift protocol/transport stack
var stm = new MemoryStream(message.rawBytes);
var trns = new TStreamTransport(stm, null);
var prot = new TBinaryProtocol(trns);
// create a processor and let him handle the call
var hndl = new MathResponsesHandler();
var proc = new BasicMathClient.Processor(hndl);
proc.Process(prot, null); // oneway only
}
}
// serves incoming responses with calculation results
internal class MathResponsesHandler : BasicMathClient.Iface
{
public void FourResults(int added, int multiplied, int subtracted, int divided)
{
Console.WriteLine("added = {0}", added);
Console.WriteLine("multiplied= {0}", multiplied);
Console.WriteLine("subtracted = {0}", subtracted);
Console.WriteLine("divided = {0}", divided);
PingAndDoAnotherCalculation();
}
public void ThreeResults(int added, int multiplied, int subtracted)
{
Console.WriteLine("added = {0}", added);
Console.WriteLine("multiplied= {0}", multiplied);
Console.WriteLine("subtracted = {0}", subtracted);
Console.WriteLine("DIV/0 error during division");
PingAndDoAnotherCalculation();
}
public void Pong(long value)
{
var latency = DateTime.Now.Ticks - value;
Console.WriteLine("Ping took {0} ms", new DateTime(latency).Millisecond);
}
private void PingAndDoAnotherCalculation()
{
var random = new Random();
var client = new MathRequestClient("localhost");
client.Ping(DateTime.Now.Ticks);
client.DoTheMath(random.Next(), random.Next());
}
}
// provides the client-side interface for calculation requests
internal class MathRequestClient : BasicMathServer.Iface
{
private BuiltinContainerAdapter MQAdapter;
public MathRequestClient(string server)
{
MQAdapter = new BuiltinContainerAdapter();
Configure.With(MQAdapter)
.Transport(t => t.UseRabbitMqInOneWayMode("amqp://" + server)) // we need send only
.MessageOwnership(o => o.FromRebusConfigurationSection())
.CreateBus().Start();
}
public void SerializeThriftCall(Action<BasicMathServer.Iface> action)
{
// Thrift protocol/transport stack
var stm = new MemoryStream();
var trns = new TStreamTransport(null, stm);
var prot = new TBinaryProtocol(trns);
// serialize the call into a bunch of bytes
var client = new BasicMathServer.Client(prot);
if( action != null)
action(client);
else
throw new ArgumentException("action must not be null");
// make sure everything is written to the MemoryStream
trns.Flush();
// send the message
var msg = new MathRequestCall() { rawBytes = stm.ToArray() };
MQAdapter.Bus.Send(msg);
}
public void Ping(long value)
{
SerializeThriftCall(client =>
{
client.Ping(value);
});
}
public void DoTheMath( int arg1, int arg2)
{
SerializeThriftCall(client =>
{
client.DoTheMath(arg1, arg2);
});
}
}
}

View file

@ -0,0 +1,143 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
using Rebus;
using Rebus.Configuration;
using Rebus.Messages;
using Rebus.RabbitMQ;
using System;
using System.Collections.Generic;
using System.IO;
using Thrift.Protocol;
using Thrift.Transport;
/*
* The server implements the BasicMathServer service .
* All results are sent back to the client via the BasicMathClient service
*/
namespace RebusSample.Server
{
// handler to be registered with Rebus
class MathRequestCallHandler : IHandleMessages<MathRequestCall>
{
public void Handle(MathRequestCall message)
{
// Thrift protocol/transport stack
var stm = new MemoryStream(message.rawBytes);
var trns = new TStreamTransport(stm, null);
var prot = new TBinaryProtocol(trns);
// create a processor and let him handle the call
var hndl = new MathRequestsHandler();
var proc = new BasicMathServer.Processor(hndl);
proc.Process(prot, null); // oneway only
}
}
// serves incoming calculation requests
internal class MathRequestsHandler : BasicMathServer.Iface
{
public void Ping(long value)
{
var client = new MathResponseClient("localhost");
client.Pong(value);
}
public void DoTheMath(int arg1, int arg2)
{
var client = new MathResponseClient("localhost");
if( arg2 != 0)
client.FourResults( arg1+arg2, arg1*arg2, arg1-arg2, arg1/arg2);
else
client.ThreeResults( arg1+arg2, arg1*arg2, arg1-arg2);
}
}
// provides the client-side interface for calculation responses
internal class MathResponseClient : BasicMathClient.Iface
{
private BuiltinContainerAdapter MQAdapter;
public MathResponseClient(string server)
{
MQAdapter = new BuiltinContainerAdapter();
Configure.With(MQAdapter)
.Transport(t => t.UseRabbitMqInOneWayMode("amqp://" + server)) // we need send only
.MessageOwnership(o => o.FromRebusConfigurationSection())
.CreateBus().Start();
}
public void SerializeThriftCall(Action<BasicMathClient.Iface> action)
{
// Thrift protocol/transport stack
var stm = new MemoryStream();
var trns = new TStreamTransport(null, stm);
var prot = new TBinaryProtocol(trns);
// serialize the call into a bunch of bytes
var client = new BasicMathClient.Client(prot);
if (action != null)
action(client);
else
throw new ArgumentException("action must not be null");
// make sure everything is written to the MemoryStream
trns.Flush();
// send the message
var msg = new MathResponseCall() { rawBytes = stm.ToArray() };
MQAdapter.Bus.Send(msg);
}
public void Pong(long value)
{
SerializeThriftCall(client =>
{
client.Pong(value);
});
}
public void ThreeResults(int added, int multiplied, int suctracted)
{
SerializeThriftCall(client =>
{
client.ThreeResults(added, multiplied, suctracted);
});
}
public void FourResults(int added, int multiplied, int suctracted, int divided)
{
SerializeThriftCall(client =>
{
client.FourResults(added, multiplied, suctracted, divided);
});
}
}
}

View file

@ -0,0 +1,30 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
service BasicMathServer {
oneway void DoTheMath( 1: i32 arg1, 2: i32 arg2)
oneway void Ping(1: i64 value)
}
service BasicMathClient {
oneway void ThreeResults( 1 : i32 added, 2 : i32 multiplied, 3 : i32 subtracted);
oneway void FourResults( 1 : i32 added, 2 : i32 multiplied, 3 : i32 subtracted, 4 : i32 divided);
oneway void Pong(1: i64 value)
}

View file

@ -0,0 +1,18 @@
Sample code for STOMP-based Thrift clients and/or servers.
Although the sample Thrift STOMP Transport is written in
Delphi/Pascal, it can easily serve as a starting point for
similar implementations in other languages.
STOMP is a protocol widely supported by many messaging systems,
such as Apache ActiveMQ, RabbitMQ and many others. In particular,
it can be used to communicate with Service-Bus products like Rebus
or NServiceBus, when running against a STOMP-capable MQ system.
A prerequisite for this sample is the Delphi STOMP Adapter written
by Daniele Teti (http://www.danieleteti.it/stomp-client), currently
hosted at Google Code (http://code.google.com/p/delphistompclient).
At the time of writing, the STOMP adapter does not fully support
binary data. Please check whether this has been fixed, otherwise
you have to use the JSON protocol (or to fix it on your own).

View file

@ -0,0 +1,200 @@
(*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*)
unit Thrift.Transport.STOMP;
interface
uses
Classes,Windows, SysUtils,
Thrift,
Thrift.Transport,
Thrift.Protocol,
Thrift.Stream,
StompClient,
StompTypes;
type
TStompTransportImpl = class( TStreamTransportImpl)
strict private
FData : TStringStream;
FServer : string;
FOutQueue : string;
FStompCli : IStompClient;
protected
function GetIsOpen: Boolean; override;
function Peek: Boolean; override;
public
constructor Create( const aServerAndPort, aOutQueue : string);
destructor Destroy; override;
procedure Open(); override;
procedure Close(); override;
procedure Flush; override;
end;
TStompServerTransportImpl = class( TServerTransportImpl)
strict private
FServer : string;
FInQueue : string;
FClient : IStompClient;
protected
procedure Listen; override;
procedure Close; override;
function Accept( const fnAccepting: TProc): ITransport; override;
public
constructor Create( const aServerAndPort, aInQueue : string);
destructor Destroy; override;
end;
const
QUEUE_PREFIX = '/queue/';
TOPIC_PREFIX = '/topic/';
EXCHANGE_PREFIX = '/exchange/';
implementation
constructor TStompTransportImpl.Create( const aServerAndPort, aOutQueue : string);
var adapter : IThriftStream;
begin
FData := TStringStream.Create;
FServer := aServerAndPort;
FOutQueue := aOutQueue;
adapter := TThriftStreamAdapterDelphi.Create( FData, FALSE);
inherited Create( nil, adapter); // output only
end;
destructor TStompTransportImpl.Destroy;
begin
inherited Destroy;
FreeAndNil( FData);
FStompCli := nil;
end;
function TStompTransportImpl.GetIsOpen: Boolean;
begin
result := (FStompCli <> nil);
end;
function TStompTransportImpl.Peek: Boolean;
begin
result := FALSE; // output only
end;
procedure TStompTransportImpl.Open;
begin
if FStompCli <> nil
then raise TTransportException.Create( TTransportException.TExceptionType.AlreadyOpen, 'already open')
else FStompCli := StompUtils.NewStomp( FServer);
end;
procedure TStompTransportImpl.Close;
begin
FStompCli := nil;
FData.Clear;
end;
procedure TStompTransportImpl.Flush;
begin
if FStompCli = nil
then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen, 'not open');
FStompCli.Send( FOutQueue, FData.DataString);
FData.Clear;
end;
//--- TStompServerTransportImpl --------------------------------------------
constructor TStompServerTransportImpl.Create( const aServerAndPort, aInQueue : string);
begin
inherited Create;
FServer := aServerAndPort;
FInQueue := aInQueue;
end;
destructor TStompServerTransportImpl.Destroy;
begin
try
Close;
finally
inherited Destroy;
end;
end;
procedure TStompServerTransportImpl.Listen;
begin
FClient := StompUtils.NewStomp(FServer);
FClient.Subscribe( FInQueue);
end;
procedure TStompServerTransportImpl.Close;
begin
if FClient <> nil then begin
FClient.Unsubscribe( FInQueue);
FClient := nil;
end;
end;
function TStompServerTransportImpl.Accept( const fnAccepting: TProc): ITransport;
var frame : IStompFrame;
adapter : IThriftStream;
stream : TStringStream;
begin
if FClient = nil
then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
'Not connected.');
if Assigned(fnAccepting)
then fnAccepting();
try
frame := FClient.Receive(MAXINT);
if frame = nil then Exit(nil);
stream := TStringStream.Create( frame.GetBody);
adapter := TThriftStreamAdapterDelphi.Create( stream, TRUE);
result := TStreamTransportImpl.Create( adapter, nil);
except
on E: Exception
do raise TTransportException.Create( E.ToString );
end;
end;
end.

133
vendor/git.apache.org/thrift.git/contrib/Vagrantfile generated vendored Normal file
View file

@ -0,0 +1,133 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
$build_and_test = <<SCRIPT
echo "Provisioning system to compile and test Apache Thrift."
# Create swap space
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
sudo swapon -s
# Update the system
sudo DEBIAN_FRONTEND=noninteractive apt-get update -qq -y
sudo DEBIAN_FRONTEND=noninteractive apt-get upgrade -qq -y
# Install Dependencies
# ---
# General dependencies
sudo apt-get install -qq automake libtool flex bison pkg-config g++ libssl-dev make libqt4-dev git debhelper
# C++ dependencies
sudo apt-get install -qq libboost-dev libboost-test-dev libboost-program-options-dev libboost-filesystem-dev libboost-system-dev libevent-dev
# Java dependencies
sudo apt-get install -qq ant openjdk-7-jdk maven
# Python dependencies
sudo apt-get install -qq python-all python-all-dev python-all-dbg python-setuptools python-support python-six python3-six
# Ruby dependencies
sudo apt-get install -qq ruby ruby-dev
sudo gem install bundler rake
# Perl dependencies
sudo apt-get install -qq libbit-vector-perl libclass-accessor-class-perl
# Php dependencies
sudo apt-get install -qq php5 php5-dev php5-cli php-pear re2c
# GlibC dependencies
sudo apt-get install -qq libglib2.0-dev
# Erlang dependencies
sudo apt-get install -qq erlang-base erlang-eunit erlang-dev erlang-tools
# GO dependencies
echo "golang-go golang-go/dashboard boolean false" | debconf-set-selections
sudo apt-get -y install -qq golang golang-go
# Haskell dependencies
sudo apt-get install -qq ghc cabal-install libghc-binary-dev libghc-network-dev libghc-http-dev libghc-hashable-dev libghc-unordered-containers-dev libghc-vector-dev
sudo cabal update
# Lua dependencies
sudo apt-get install -qq lua5.2 lua5.2-dev
# Node.js dependencies
sudo apt-get install -qq nodejs nodejs-dev nodejs-legacy npm
# CSharp
sudo apt-get install -qq mono-gmcs mono-devel mono-xbuild mono-complete libmono-system-web2.0-cil
sudo apt-get install -qq mingw32 mingw32-binutils mingw32-runtime nsis
# D dependencies
sudo wget http://master.dl.sourceforge.net/project/d-apt/files/d-apt.list -O /etc/apt/sources.list.d/d-apt.list
sudo apt-get update && sudo apt-get -y --allow-unauthenticated install --reinstall d-apt-keyring && sudo apt-get update
sudo apt-get install -qq xdg-utils dmd-bin
# Customize the system
# ---
# Default java to latest 1.7 version
update-java-alternatives -s java-1.7.0-openjdk-amd64
# PHPUnit package broken in ubuntu. see https://bugs.launchpad.net/ubuntu/+source/phpunit/+bug/701544
sudo apt-get upgrade pear
sudo pear channel-discover pear.phpunit.de
sudo pear channel-discover pear.symfony.com
sudo pear channel-discover components.ez.no
sudo pear update-channels
sudo pear upgrade-all
sudo pear install --alldeps phpunit/PHPUnit
date > /etc/vagrant.provisioned
# Start the source build
# ---
echo "Starting Apache Thrift build..."
cd /thrift
sh bootstrap.sh
sh configure
make
make check
echo "Finished building Apache Thrift."
SCRIPT
Vagrant.configure("2") do |config|
# Ubuntu 14.04 LTS (Trusty Tahr)
config.vm.box = "trusty64"
config.vm.box_url = "https://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box"
config.vm.synced_folder "../", "/thrift"
config.vm.provider :virtualbox do |vbox|
vbox.customize ["modifyvm", :id, "--memory", "1024"]
vbox.customize ["modifyvm", :id, "--cpus", "2"]
vbox.customize ["modifyvm", :id, "--rtcuseutc", "on"]
end
# Run the build script to configure the system
config.vm.provision :shell, :inline => $build_and_test
end

View file

@ -0,0 +1,8 @@
exception Error {
1: string desc;
}
service Aggr {
void addValue(1: i32 value);
list<i32> getValues() throws (1: Error err);
}

View file

@ -0,0 +1,24 @@
#!/usr/bin/env python
import sys
import time
from thrift.transport import TTransport
from thrift.transport import TSocket
from thrift.protocol import TBinaryProtocol
from thrift.server import THttpServer
from aggr import Aggr
class AggrHandler(Aggr.Iface):
def __init__(self):
self.values = []
def addValue(self, value):
self.values.append(value)
def getValues(self, ):
time.sleep(1)
return self.values
processor = Aggr.Processor(AggrHandler())
pfactory = TBinaryProtocol.TBinaryProtocolFactory()
THttpServer.THttpServer(processor, ('', int(sys.argv[1])), pfactory).serve()

View file

@ -0,0 +1,97 @@
#include <tr1/functional>
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/async/TAsyncProtocolProcessor.h>
#include <thrift/async/TEvhttpServer.h>
#include <thrift/async/TEvhttpClientChannel.h>
#include "Aggr.h"
using std::tr1::bind;
using std::tr1::placeholders::_1;
using apache::thrift::TException;
using apache::thrift::protocol::TBinaryProtocolFactory;
using apache::thrift::protocol::TProtocolFactory;
using apache::thrift::async::TEvhttpServer;
using apache::thrift::async::TAsyncProcessor;
using apache::thrift::async::TAsyncBufferProcessor;
using apache::thrift::async::TAsyncProtocolProcessor;
using apache::thrift::async::TAsyncChannel;
using apache::thrift::async::TEvhttpClientChannel;
class AggrAsyncHandler : public AggrCobSvIf {
protected:
struct RequestContext {
std::tr1::function<void(std::vector<int32_t> const& _return)> cob;
std::vector<int32_t> ret;
int pending_calls;
};
public:
AggrAsyncHandler()
: eb_(NULL)
, pfact_(new TBinaryProtocolFactory())
{
leaf_ports_.push_back(8081);
leaf_ports_.push_back(8082);
}
void addValue(std::tr1::function<void()> cob, const int32_t value) {
// Silently drop writes to the aggrgator.
return cob();
}
void getValues(std::tr1::function<void(
std::vector<int32_t> const& _return)> cob,
std::tr1::function<void(::apache::thrift::TDelayedException* _throw)> exn_cob) {
RequestContext* ctx = new RequestContext();
ctx->cob = cob;
ctx->pending_calls = leaf_ports_.size();
for (std::vector<int>::iterator it = leaf_ports_.begin();
it != leaf_ports_.end(); ++it) {
boost::shared_ptr<TAsyncChannel> channel(
new TEvhttpClientChannel(
"localhost", "/", "127.0.0.1", *it, eb_));
AggrCobClient* client = new AggrCobClient(channel, pfact_.get());
client->getValues(std::tr1::bind(&AggrAsyncHandler::clientReturn, this, ctx, _1));
}
}
void setEventBase(struct event_base* eb) {
eb_ = eb;
}
void clientReturn(RequestContext* ctx, AggrCobClient* client) {
ctx->pending_calls -= 1;
try {
std::vector<int32_t> subret;
client->recv_getValues(subret);
ctx->ret.insert(ctx->ret.end(), subret.begin(), subret.end());
} catch (TException& exn) {
// TODO: Log error
}
delete client;
if (ctx->pending_calls == 0) {
ctx->cob(ctx->ret);
delete ctx;
}
}
protected:
struct event_base* eb_;
std::vector<int> leaf_ports_;
boost::shared_ptr<TProtocolFactory> pfact_;
};
int main() {
boost::shared_ptr<AggrAsyncHandler> handler(new AggrAsyncHandler());
boost::shared_ptr<TAsyncProcessor> proc(new AggrAsyncProcessor(handler));
boost::shared_ptr<TProtocolFactory> pfact(new TBinaryProtocolFactory());
boost::shared_ptr<TAsyncBufferProcessor> bufproc(new TAsyncProtocolProcessor(proc, pfact));
boost::shared_ptr<TEvhttpServer> server(new TEvhttpServer(bufproc, 8080));
handler->setEventBase(server->getEventBase());
server->serve();
}

16
vendor/git.apache.org/thrift.git/contrib/fb303/LICENSE generated vendored Normal file
View file

@ -0,0 +1,16 @@
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.

View file

@ -0,0 +1,46 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
@GLOBAL_HEADER_MK@
@PRODUCT_MK@
SUBDIRS = .
if WITH_CPP
SUBDIRS += cpp
endif
if WITH_JAVA
SUBDIRS += java
endif
if WITH_PHP
SUBDIRS += php
endif
if WITH_PYTHON
SUBDIRS += py
endif
BUILT_SOURCES =
clean-local: clean-common
@GLOBAL_FOOTER_MK@

View file

@ -0,0 +1,37 @@
Project FB303: The Facebook Bassline
------------------------------------
* Curious about the 303? *
http://en.wikipedia.org/wiki/Roland_TB-303
* Why the name? *
The TB303 makes bass lines.
.Bass is what lies underneath any strong tune.
..fb303 is the shared root of all thrift services.
...fb303 => FacebookBase303.
* How do I use this? *
Take a look at the examples to see how your backend project can
and should inherit from this service.
* What does it provide? *
A standard interface to monitoring, dynamic options and configuration,
uptime reports, activity, etc.
* I want more. *
Think carefully first about whether the functionality you are going to add
belongs here or in your application. If it can be abstracted and is generally
useful, then it probably belongs somewhere in the fb303 tree. Keep in mind,
not every product has to use ALL the functionality of fb303, but every product
CANNOT use functionality that is NOT in fb303.
* Is this open source? *
Yes. fb303 is distributed under the Thrift Software License. See the
LICENSE file for more details.
* Installation *
fb303 is configured/built/installed similar to Thrift. See the README
in the Thrift root directory for more information.
* Who wrote this README? *
mcslee@facebook.com

View file

@ -0,0 +1,178 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include <thrift/server/TClientInfo.h>
namespace apache { namespace thrift { namespace server {
using namespace apache::thrift;
using namespace apache::thrift::transport;
TClientInfoConnection::TClientInfoConnection() {
call_[kNameLen - 1] = '\0'; // insure NUL terminator is there
eraseAddr();
eraseCall();
}
void TClientInfoConnection::recordAddr(const sockaddr* addr) {
eraseAddr();
initTime();
ncalls_ = 0;
if (addr != NULL) {
if (addr->sa_family == AF_INET) {
memcpy((void*)&addr_.ipv4, (const void *)addr, sizeof(sockaddr_in));
}
else if (addr->sa_family == AF_INET6) {
memcpy((void*)&addr_.ipv6, (const void *)addr, sizeof(sockaddr_in6));
}
}
}
void TClientInfoConnection::eraseAddr() {
addr_.ipv4.sin_family = AF_UNSPEC;
}
const char* TClientInfoConnection::getAddr(char* buf, int len) const {
switch (addr_.ipv4.sin_family) {
case AF_INET:
return inet_ntop(AF_INET, &addr_.ipv4.sin_addr, buf, len);
case AF_INET6:
return inet_ntop(AF_INET6, &addr_.ipv6.sin6_addr, buf, len);
default:
return NULL;
}
}
void TClientInfoConnection::recordCall(const char* name) {
strncpy(call_, name, kNameLen - 1); // NUL terminator set in constructor
ncalls_++;
}
void TClientInfoConnection::eraseCall() {
call_[0] = '\0';
}
const char* TClientInfoConnection::getCall() const {
if (call_[0] == '\0') {
return NULL;
}
return call_;
}
void TClientInfoConnection::getTime(timespec* time) const {
*time = time_;
}
uint64_t TClientInfoConnection::getNCalls() const {
return ncalls_;
}
void TClientInfoConnection::initTime() {
clock_gettime(CLOCK_REALTIME, &time_);
}
TClientInfoConnection* TClientInfo::getConnection(int fd, bool grow) {
if (fd < 0 || (!grow && fd >= info_.size())) {
return NULL;
}
return &info_[fd];
}
size_t TClientInfo::size() const {
return info_.size();
}
void* TClientInfoServerHandler::createContext(boost::shared_ptr<TProtocol> input,
boost::shared_ptr<TProtocol> output) {
(void)input;
(void)output;
return (void*) new Connect(&clientInfo_);
}
void TClientInfoServerHandler::deleteContext(void* connectionContext,
boost::shared_ptr<TProtocol> input,
boost::shared_ptr<TProtocol> output) {
Connect* call = static_cast<Connect*>(connectionContext);
if (call->callInfo_) {
call->callInfo_->eraseCall();
}
delete call;
}
void TClientInfoServerHandler::processContext(void* connectionContext,
shared_ptr<TTransport> transport) {
Connect* call = static_cast<Connect*>(connectionContext);
if (call->callInfo_ == NULL) {
if (typeid(*(transport.get())) == typeid(TSocket)) {
TSocket* tsocket = static_cast<TSocket*>(transport.get());
int fd = tsocket->getSocketFD();
if (fd < 0) {
return;
}
call->callInfo_ = call->clientInfo_->getConnection(fd, true);
assert(call->callInfo_ != NULL);
socklen_t len;
call->callInfo_->recordAddr(tsocket->getCachedAddress(&len));
}
}
}
void TClientInfoServerHandler::getStatsStrings(vector<string>& result) {
result.clear();
timespec now;
clock_gettime(CLOCK_REALTIME, &now);
for (int i = 0; i < clientInfo_.size(); ++i) {
TClientInfoConnection* info = clientInfo_.getConnection(i, false);
const char* callStr = info->getCall();
if (callStr == NULL) {
continue;
}
char addrBuf[INET6_ADDRSTRLEN];
const char* addrStr = info->getAddr(addrBuf, sizeof addrBuf);
if (addrStr == NULL) {
// cerr << "no addr!" << endl;
continue;
}
timespec start;
info->getTime(&start);
double secs = (double)(now.tv_sec - start.tv_sec) + (now.tv_nsec - start.tv_nsec)*0.000000001;
char buf[256];
snprintf(buf, sizeof buf, "%d %s %s %.3f %llu", i, addrStr, callStr, secs,
(uint64_t)info->getNCalls());
result.push_back(buf);
}
}
void* TClientInfoCallHandler::getContext(const char* fn_name, void* serverContext) {
if (serverContext) {
TClientInfoConnection* callInfo = static_cast<TClientInfoServerHandler::Connect*>(serverContext)->callInfo_;
if (callInfo != NULL) {
callInfo->recordCall(fn_name);
}
}
return NULL;
}
} } } // namespace apache::thrift::server

View file

@ -0,0 +1,320 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#ifndef _FACEBOOK_THRIFT_SERVER_TCLIENTINFO_H_
#define _FACEBOOK_THRIFT_SERVER_TCLIENTINFO_H_ 1
// for inet_ntop --
#include <arpa/inet.h>
#include <thrift/server/TServer.h>
#include <thrift/transport/TSocket.h>
#include <thrift/concurrency/Mutex.h>
namespace apache { namespace thrift { namespace server {
using namespace apache::thrift;
using namespace apache::thrift::transport;
using namespace apache::thrift::concurrency;
using boost::shared_ptr;
using std::string;
using std::vector;
/**
* StableVector -- a minimal vector class where growth is automatic and
* vector elements never move as the vector grows. Allocates new space
* as needed, but does not copy old values.
*
* A level vector stores a list of storage vectors containing the actual
* elements. Levels are added as needed, doubling in size each time.
* Locking is only done when a level is added. Access is amortized
* constant time.
*/
template <typename T>
class StableVector {
/// The initial allocation as an exponent of 2
static const uint32_t kInitialSizePowOf2 = 10;
/// The initial allocation size
static const uint32_t kInitialVectorSize = 1 << kInitialSizePowOf2;
/// This bound is guaranteed not to be exceeded on 64-bit archs
static const int kMaxLevels = 64;
/// Values are kept in one or more of these
typedef vector<T> Vect;
/// One or more value vectors are kept in one of these
typedef vector<Vect*> LevelVector;
Mutex mutex_;
/// current size
size_t size_;
_Atomic_word vectLvl_;
LevelVector vects_;
public:
/**
* Constructor -- initialize the level vector and allocate the
* initial storage vector
*/
StableVector()
: size_(0)
, vectLvl_(0) {
vects_.reserve(kMaxLevels);
Vect* storageVector(new Vect(1 << kInitialSizePowOf2));
vects_.push_back(storageVector);
}
private:
/**
* make sure the requested number of storage levels have been allocated.
*/
void expand(uint32_t level) {
// we need the guard to insure that we only allocate once.
Guard g(mutex_);
while (level > vectLvl_) {
Vect* levelVect(new Vect(1 << (vectLvl_ + kInitialSizePowOf2)));
vects_.push_back(levelVect);
// we need to make sure this is done after levelVect is inserted
// (what we want is effectively a memory barrier here).
__gnu_cxx::__atomic_add(&vectLvl_, 1);
}
}
/**
* Given an index, determine which level and element of that level is
* required. Grows if needed.
*/
void which(uint32_t n, uint32_t* vno, uint32_t* idx) {
if (n >= size_) {
size_ = n + 1;
}
if (n < kInitialVectorSize) {
*idx = n;
*vno = 0;
} else {
uint32_t upper = n >> kInitialSizePowOf2;
*vno = CHAR_BIT*sizeof(upper) - __builtin_clz(upper);
*idx = n - (1 << (*vno + kInitialSizePowOf2 - 1));
if (*vno > vectLvl_) {
expand(*vno);
}
}
}
public:
/**
* Given an index, return a reference to that element, perhaps after
* allocating additional space.
*
* @param n a positive integer
*/
T& operator[](uint32_t n) {
uint32_t vno;
uint32_t idx;
which(n, &vno, &idx);
return (*vects_[vno])[idx];
}
/**
* Return the present size of the vector.
*/
size_t size() const { return size_; }
};
/**
* This class embodies the representation of a single connection during
* processing. We'll keep one of these per file descriptor in TClientInfo.
*/
class TClientInfoConnection {
public:
const static int kNameLen = 32;
private:
typedef union IPAddrUnion {
sockaddr_in ipv4;
sockaddr_in6 ipv6;
};
char call_[kNameLen]; ///< The name of the thrift call
IPAddrUnion addr_; ///< The client's IP address
timespec time_; ///< Time processing started
uint64_t ncalls_; ///< # of calls processed
public:
/**
* Constructor; insure that no client address or thrift call name is
* represented.
*/
TClientInfoConnection();
/**
* A connection has been made; record its address. Since this is the
* first we'll know of a connection we start the timer here as well.
*/
void recordAddr(const sockaddr* addr);
/**
* Mark the address as empty/unknown.
*/
void eraseAddr();
/**
* Return a string representing the present address, or NULL if none.
* Copies the string into the buffer provided.
*/
const char* getAddr(char* buf, int len) const;
/**
* A call has been made on this connection; record its name. Since this is
* called for every thrift call processed, we also do our call count here.
*/
void recordCall(const char* name);
/**
* Invoked when processing has ended to clear the call name.
*/
void eraseCall();
/**
* Return as string the thrift call either currently being processed or
* most recently processed if the connection is still open for additional
* calls. Returns NULL if a call hasn't been made yet or processing
* has ended.
*/
const char* getCall() const;
/**
* Get the timespec for the start of this connection (specifically, when
* recordAddr() was first called).
*/
void getTime(timespec* time) const;
/**
* Return the number of calls made on this connection.
*/
uint64_t getNCalls() const;
private:
void initTime();
};
/**
* Store for info about a server's clients -- specifically, the client's IP
* address and the call it is executing. This information is indexed by
* socket file descriptor and in the present implementation is updated
* asynchronously, so it may only approximate reality.
*/
class TClientInfo {
private:
StableVector<TClientInfoConnection> info_;
public:
/**
* Return the info object for a given file descriptor. If "grow" is true
* extend the info vector if required (such as for a file descriptor not seen
* before). If "grow" is false and the info vector isn't large enough,
* or if "fd" is negative, return NULL.
*/
TClientInfoConnection* getConnection(int fd, bool grow);
size_t size() const;
};
/**
* This derivation of TServerEventHandler encapsulates the main status vector
* and provides context to the server's processing loop via overrides.
* Together with TClientInfoCallHandler (derived from TProcessorEventHandler)
* it integrates client info collection into the server.
*/
class TClientInfoServerHandler : public TServerEventHandler {
private:
TClientInfo clientInfo_;
public:
/**
* One of these is constructed for each open connection/descriptor and links
* to both the status vector (clientInfo_) and that descriptor's entry
* within it.
*/
struct Connect {
TClientInfo* clientInfo_;
TClientInfoConnection* callInfo_;
explicit Connect(TClientInfo* clientInfo)
: clientInfo_(clientInfo)
, callInfo_(NULL) {
}
};
/**
* Generate processor context; we don't know what descriptor we belong to
* yet -- we'll get hooked up in contextProcess().
*/
void* createContext(boost::shared_ptr<TProtocol> input,
boost::shared_ptr<TProtocol> output);
/**
* Mark our slot as unused and delete the context created in createContext().
*/
void deleteContext(void* processorContext,
boost::shared_ptr<TProtocol> input,
boost::shared_ptr<TProtocol> output);
/**
* Called in the processing loop just before the server invokes the
* processor itself, on the first call we establish which descriptor
* we correspond to and set it to that socket's peer IP address. This
* also has the side effect of initializing call counting and connection
* timing. We won't know which call we're handling until the handler
* first gets called in TClientInfoCallHandler::getContext().
*/
void processContext(void* processorContext,
shared_ptr<TTransport> transport);
/**
* Get status report for server in the form of a vector of strings.
* Each active client appears as one string in the format:
*
* FD IPADDR CALLNAME DURATION NCALLS
*
* where "FD" is the file descriptor for the client's socket, "IPADDR"
* is the IP address (as reported by accept()), "CALLNAME" is the
* current or most recent Thrift function name, "DURATION" is the
* duration of the connection, while NCALLS is the number of Thrift
* calls made since the connection was made. A single space separates
* fields.
*/
void getStatsStrings(vector<string>& result);
};
/**
* This class derives from TProcessorEventHandler to gain access to the
* function name for the current Thrift call. We need two versions of
* this -- TClientInfoCallStatsHandler is the other -- since in the latter
* case we pass through to TFunctionStatHandler to perform Thrift call
* stats.
*/
class TClientInfoCallHandler : public TProcessorEventHandler {
public:
virtual void* getContext(const char* fn_name, void* serverContext);
};
} } } // namespace apache::thrift::server
#endif // !_FACEBOOK_THRIFT_SERVER_TCLIENTINFO_H_

View file

@ -0,0 +1,198 @@
##### http://autoconf-archive.cryp.to/ax_boost_base.html
#
# SYNOPSIS
#
# AX_BOOST_BASE([MINIMUM-VERSION])
#
# DESCRIPTION
#
# Test for the Boost C++ libraries of a particular version (or newer)
#
# If no path to the installed boost library is given the macro
# searchs under /usr, /usr/local, /opt and /opt/local and evaluates
# the $BOOST_ROOT environment variable. Further documentation is
# available at <http://randspringer.de/boost/index.html>.
#
# This macro calls:
#
# AC_SUBST(BOOST_CPPFLAGS) / AC_SUBST(BOOST_LDFLAGS)
#
# And sets:
#
# HAVE_BOOST
#
# LAST MODIFICATION
#
# 2007-07-28
#
# COPYLEFT
#
# Copyright (c) 2007 Thomas Porschberg <thomas@randspringer.de>
#
# Copying and distribution of this file, with or without
# modification, are permitted in any medium without royalty provided
# the copyright notice and this notice are preserved.
AC_DEFUN([AX_BOOST_BASE],
[
AC_ARG_WITH([boost],
AS_HELP_STRING([--with-boost@<:@=DIR@:>@], [use boost (default is yes) - it is possible to specify the root directory for boost (optional)]),
[
if test "$withval" = "no"; then
want_boost="no"
elif test "$withval" = "yes"; then
want_boost="yes"
ac_boost_path=""
else
want_boost="yes"
ac_boost_path="$withval"
fi
],
[want_boost="yes"])
if test "x$want_boost" = "xyes"; then
boost_lib_version_req=ifelse([$1], ,1.20.0,$1)
boost_lib_version_req_shorten=`expr $boost_lib_version_req : '\([[0-9]]*\.[[0-9]]*\)'`
boost_lib_version_req_major=`expr $boost_lib_version_req : '\([[0-9]]*\)'`
boost_lib_version_req_minor=`expr $boost_lib_version_req : '[[0-9]]*\.\([[0-9]]*\)'`
boost_lib_version_req_sub_minor=`expr $boost_lib_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'`
if test "x$boost_lib_version_req_sub_minor" = "x" ; then
boost_lib_version_req_sub_minor="0"
fi
WANT_BOOST_VERSION=`expr $boost_lib_version_req_major \* 100000 \+ $boost_lib_version_req_minor \* 100 \+ $boost_lib_version_req_sub_minor`
AC_MSG_CHECKING(for boostlib >= $boost_lib_version_req)
succeeded=no
dnl first we check the system location for boost libraries
dnl this location ist chosen if boost libraries are installed with the --layout=system option
dnl or if you install boost with RPM
if test "$ac_boost_path" != ""; then
BOOST_LDFLAGS="-L$ac_boost_path/lib"
BOOST_CPPFLAGS="-I$ac_boost_path/include"
else
for ac_boost_path_tmp in /usr /usr/local /opt /opt/local ; do
if test -d "$ac_boost_path_tmp/include/boost" && test -r "$ac_boost_path_tmp/include/boost"; then
BOOST_LDFLAGS="-L$ac_boost_path_tmp/lib"
BOOST_CPPFLAGS="-I$ac_boost_path_tmp/include"
break;
fi
done
fi
CPPFLAGS_SAVED="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
export CPPFLAGS
LDFLAGS_SAVED="$LDFLAGS"
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
export LDFLAGS
AC_LANG_PUSH(C++)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
@%:@include <boost/version.hpp>
]], [[
#if BOOST_VERSION >= $WANT_BOOST_VERSION
// Everything is okay
#else
# error Boost version is too old
#endif
]])],[
AC_MSG_RESULT(yes)
succeeded=yes
found_system=yes
],[
])
AC_LANG_POP([C++])
dnl if we found no boost with system layout we search for boost libraries
dnl built and installed without the --layout=system option or for a staged(not installed) version
if test "x$succeeded" != "xyes"; then
_version=0
if test "$ac_boost_path" != ""; then
BOOST_LDFLAGS="-L$ac_boost_path/lib"
if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then
for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do
_version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
V_CHECK=`expr $_version_tmp \> $_version`
if test "$V_CHECK" = "1" ; then
_version=$_version_tmp
fi
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE"
done
fi
else
for ac_boost_path in /usr /usr/local /opt /opt/local ; do
if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then
for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do
_version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
V_CHECK=`expr $_version_tmp \> $_version`
if test "$V_CHECK" = "1" ; then
_version=$_version_tmp
best_path=$ac_boost_path
fi
done
fi
done
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE"
BOOST_LDFLAGS="-L$best_path/lib"
if test "x$BOOST_ROOT" != "x"; then
if test -d "$BOOST_ROOT" && test -r "$BOOST_ROOT" && test -d "$BOOST_ROOT/stage/lib" && test -r "$BOOST_ROOT/stage/lib"; then
version_dir=`expr //$BOOST_ROOT : '.*/\(.*\)'`
stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'`
stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'`
V_CHECK=`expr $stage_version_shorten \>\= $_version`
if test "$V_CHECK" = "1" ; then
AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT)
BOOST_CPPFLAGS="-I$BOOST_ROOT"
BOOST_LDFLAGS="-L$BOOST_ROOT/stage/lib"
fi
fi
fi
fi
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
export CPPFLAGS
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
export LDFLAGS
AC_LANG_PUSH(C++)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
@%:@include <boost/version.hpp>
]], [[
#if BOOST_VERSION >= $WANT_BOOST_VERSION
// Everything is okay
#else
# error Boost version is too old
#endif
]])],[
AC_MSG_RESULT(yes)
succeeded=yes
found_system=yes
],[
])
AC_LANG_POP([C++])
fi
if test "$succeeded" != "yes" ; then
if test "$_version" = "0" ; then
AC_MSG_ERROR([[We could not detect the boost libraries (version $boost_lib_version_req_shorten or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in <boost/version.hpp>. See http://randspringer.de/boost for more documentation.]])
else
AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).])
fi
else
AC_SUBST(BOOST_CPPFLAGS)
AC_SUBST(BOOST_LDFLAGS)
AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available])
fi
CPPFLAGS="$CPPFLAGS_SAVED"
LDFLAGS="$LDFLAGS_SAVED"
fi
])

View file

@ -0,0 +1,134 @@
# ============================================================================
# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html
# ============================================================================
#
# SYNOPSIS
#
# AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional])
#
# DESCRIPTION
#
# Check for baseline language coverage in the compiler for the C++11
# standard; if necessary, add switches to CXXFLAGS to enable support.
#
# The first argument, if specified, indicates whether you insist on an
# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
# -std=c++11). If neither is specified, you get whatever works, with
# preference for an extended mode.
#
# The second argument, if specified 'mandatory' or if left unspecified,
# indicates that baseline C++11 support is required and that the macro
# should error out if no mode with that support is found. If specified
# 'optional', then configuration proceeds regardless, after defining
# HAVE_CXX11 if and only if a supporting mode is found.
#
# LICENSE
#
# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 3
m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [
template <typename T>
struct check
{
static_assert(sizeof(int) <= sizeof(T), "not big enough");
};
typedef check<check<bool>> right_angle_brackets;
int a;
decltype(a) b;
typedef check<int> check_type;
check_type c;
check_type&& cr = static_cast<check_type&&>(c);
auto d = a;
])
AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl
m4_if([$1], [], [],
[$1], [ext], [],
[$1], [noext], [],
[m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl
m4_if([$2], [], [ax_cxx_compile_cxx11_required=true],
[$2], [mandatory], [ax_cxx_compile_cxx11_required=true],
[$2], [optional], [ax_cxx_compile_cxx11_required=false],
[m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])])dnl
AC_LANG_PUSH([C++])dnl
ac_success=no
AC_CACHE_CHECK(whether $CXX supports C++11 features by default,
ax_cv_cxx_compile_cxx11,
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
[ax_cv_cxx_compile_cxx11=yes],
[ax_cv_cxx_compile_cxx11=no])])
if test x$ax_cv_cxx_compile_cxx11 = xyes; then
ac_success=yes
fi
m4_if([$1], [noext], [], [dnl
if test x$ac_success = xno; then
for switch in -std=gnu++11; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
$cachevar,
[ac_save_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$CXXFLAGS $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXXFLAGS="$ac_save_CXXFLAGS"])
if eval test x\$$cachevar = xyes; then
CXXFLAGS="$CXXFLAGS $switch"
ac_success=yes
break
fi
done
fi])
m4_if([$1], [ext], [], [dnl
if test x$ac_success = xno; then
for switch in -std=c++11; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
$cachevar,
[ac_save_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$CXXFLAGS $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXXFLAGS="$ac_save_CXXFLAGS"])
if eval test x\$$cachevar = xyes; then
CXXFLAGS="$CXXFLAGS $switch"
ac_success=yes
break
fi
done
fi])
AC_LANG_POP([C++])
if test x$ax_cxx_compile_cxx11_required = xtrue; then
if test x$ac_success = xno; then
AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.])
fi
else
if test x$ac_success = xno; then
HAVE_CXX11=0
AC_MSG_NOTICE([No compiler with C++11 support was found])
else
HAVE_CXX11=1
AC_DEFINE(HAVE_CXX11,1,
[define if the compiler supports basic C++11 syntax])
fi
AC_SUBST(HAVE_CXX11)
fi
])

View file

@ -0,0 +1,121 @@
dnl @synopsis AX_JAVAC_AND_JAVA
dnl @synopsis AX_CHECK_JAVA_CLASS(CLASSNAME)
dnl
dnl Test for the presence of a JDK, and (optionally) specific classes.
dnl
dnl If "JAVA" is defined in the environment, that will be the only
dnl java command tested. Otherwise, a hard-coded list will be used.
dnl Similarly for "JAVAC".
dnl
dnl AX_JAVAC_AND_JAVA does not currently support testing for a particular
dnl Java version, testing for only one of "java" and "javac", or
dnl compiling or running user-provided Java code.
dnl
dnl After AX_JAVAC_AND_JAVA runs, the shell variables "success" and
dnl "ax_javac_and_java" are set to "yes" or "no", and "JAVAC" and
dnl "JAVA" are set to the appropriate commands.
dnl
dnl AX_CHECK_JAVA_CLASS must be run after AX_JAVAC_AND_JAVA.
dnl It tests for the presence of a class based on a fully-qualified name.
dnl It sets the shell variable "success" to "yes" or "no".
dnl
dnl @category Java
dnl @version 2009-02-09
dnl @license AllPermissive
dnl
dnl Copyright (C) 2009 David Reiss
dnl Copying and distribution of this file, with or without modification,
dnl are permitted in any medium without royalty provided the copyright
dnl notice and this notice are preserved.
AC_DEFUN([AX_JAVAC_AND_JAVA],
[
dnl Hard-coded default commands to test.
JAVAC_PROGS="javac,jikes,gcj -C"
JAVA_PROGS="java,kaffe"
dnl Allow the user to specify an alternative.
if test -n "$JAVAC" ; then
JAVAC_PROGS="$JAVAC"
fi
if test -n "$JAVA" ; then
JAVA_PROGS="$JAVA"
fi
AC_MSG_CHECKING(for javac and java)
echo "public class configtest_ax_javac_and_java { public static void main(String args@<:@@:>@) { } }" > configtest_ax_javac_and_java.java
success=no
oIFS="$IFS"
IFS=","
for JAVAC in $JAVAC_PROGS ; do
IFS="$oIFS"
echo "Running \"$JAVAC configtest_ax_javac_and_java.java\"" >&AS_MESSAGE_LOG_FD
if $JAVAC configtest_ax_javac_and_java.java >&AS_MESSAGE_LOG_FD 2>&1 ; then
IFS=","
for JAVA in $JAVA_PROGS ; do
IFS="$oIFS"
echo "Running \"$JAVA configtest_ax_javac_and_java\"" >&AS_MESSAGE_LOG_FD
if $JAVA configtest_ax_javac_and_java >&AS_MESSAGE_LOG_FD 2>&1 ; then
success=yes
break 2
fi
done
fi
done
rm -f configtest_ax_javac_and_java.java configtest_ax_javac_and_java.class
if test "$success" != "yes" ; then
AC_MSG_RESULT(no)
JAVAC=""
JAVA=""
else
AC_MSG_RESULT(yes)
fi
ax_javac_and_java="$success"
])
AC_DEFUN([AX_CHECK_JAVA_CLASS],
[
AC_MSG_CHECKING(for Java class [$1])
echo "import $1; public class configtest_ax_javac_and_java { public static void main(String args@<:@@:>@) { } }" > configtest_ax_javac_and_java.java
echo "Running \"$JAVAC configtest_ax_javac_and_java.java\"" >&AS_MESSAGE_LOG_FD
if $JAVAC configtest_ax_javac_and_java.java >&AS_MESSAGE_LOG_FD 2>&1 ; then
AC_MSG_RESULT(yes)
success=yes
else
AC_MSG_RESULT(no)
success=no
fi
rm -f configtest_ax_javac_and_java.java configtest_ax_javac_and_java.class
])
AC_DEFUN([AX_CHECK_ANT_VERSION],
[
AC_MSG_CHECKING(for ant version > $2)
ANT_VALID=`expr $($1 -version 2>/dev/null | sed -n 's/.*version \(@<:@0-9\.@:>@*\).*/\1/p') \>= $2`
if test "x$ANT_VALID" = "x1" ; then
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
ANT=""
fi
])

View file

@ -0,0 +1,28 @@
dnl @synopsis AX_THRIFT_GEN(SHORT_LANGUAGE, LONG_LANGUAGE, DEFAULT)
dnl @synopsis AX_THRIFT_LIB(SHORT_LANGUAGE, LONG_LANGUAGE, DEFAULT)
dnl
dnl Allow a particular language generator to be disabled.
dnl Allow a particular language library to be disabled.
dnl
dnl These macros have poor error handling and are poorly documented.
dnl They are intended only for internal use by the Thrift compiler.
dnl
dnl @version 2008-02-20
dnl @license AllPermissive
dnl
dnl Copyright (C) 2009 David Reiss
dnl Copying and distribution of this file, with or without modification,
dnl are permitted in any medium without royalty provided the copyright
dnl notice and this notice are preserved.
AC_DEFUN([AX_THRIFT_LIB],
[
AC_ARG_WITH($1,
AC_HELP_STRING([--with-$1], [build the $2 library @<:@default=$3@:>@]),
[with_$1="$withval"],
[with_$1=$3]
)
have_$1=no
dnl What we do here is going to vary from library to library,
dnl so we can't really generalize (yet!).
])

26
vendor/git.apache.org/thrift.git/contrib/fb303/bootstrap.sh generated vendored Executable file
View file

@ -0,0 +1,26 @@
#!/bin/sh
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
# To be safe include -I flag
aclocal -I ./aclocal
automake -a
autoconf
./configure --config-cache $*

View file

@ -0,0 +1,164 @@
# Autoconf input file
# $Id$
# AC - autoconf
# FB - facebook
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
#########################################################################
# DO NOT TOUCH EXCEPT TO CHANGE REV# IN AC_INIT
AC_PREREQ(2.52)
AC_INIT([libfb303],[20080209])
#AC_CONFIG_AUX_DIR([/usr/share/automake-1.9])
# To install locally
FB_INITIALIZE([localinstall])
AC_PREFIX_DEFAULT([/usr/local])
############################################################################
# User Configurable. Change With CAUTION!
# User can include custom makefile rules. Uncomment and update only <name> in PRODUCT_MK.
# Include where appropriate in any Makefile.am as @PRODUCT_MK@
#PRODUCT_MK="include ${EXTERNAL_PATH}/shared/build/<name>.mk"
# Default path to external Facebook components and shared build toools I.e fb303 etc.
# To point to other locations set environment variable EXTERNAL_PATH.
# To change the current default you must change bootstrap.sh.
FB_WITH_EXTERNAL_PATH([`pwd`])
AC_ARG_VAR([PY_PREFIX], [Prefix for installing Python modules.
(Normal --prefix is ignored for Python because
Python has different conventions.)
Default = "/usr"])
AS_IF([test "x$PY_PREFIX" = x], [PY_PREFIX="/usr"])
##########################################################################
# User Configurable
# Pre-defined macro to set opt build mode. Run with --disable-shared option to turn off optimization.
FB_ENABLE_DEFAULT_OPT_BUILD
# Predefined macro to set static library mode. Run with --disable-static option to turn off static lib mode.
FB_ENABLE_DEFAULT_STATIC
# Personalized feature generator. Creates defines/conditionals and --enable --disable command line options.
# FB_ENABLE_FEATURE([FEATURE], [feature]) OR FB_ENABLE_FEATURE([FEATURE], [feature], [\"<value>\"])
# Example: Macro supplies -DFACEBOOK at compile time and "if FACEBOOK endif" capabilities.
# Personalized path generator Sets default paths. Provides --with-xx=DIR options.
# FB_WITH_PATH([<var>_home], [<var>path], [<default location>]
# Example: sets $(thrift_home) variable with default path set to /usr/local.
FB_WITH_PATH([thrift_home], [thriftpath], [/usr/local])
AX_CXX_COMPILE_STDCXX_11([noext])
AX_THRIFT_LIB(cpp, [C++], yes)
have_cpp=no
if test "$with_cpp" = "yes"; then
# Require boost 1.40.0 or later
AX_BOOST_BASE([1.40.0])
if test "x$succeeded" = "xyes"; then
have_cpp="yes"
fi
fi
AM_CONDITIONAL([WITH_CPP], [test "$have_cpp" = "yes"])
AX_THRIFT_LIB(java, [Java], yes)
if test "$with_java" = "yes"; then
AX_JAVAC_AND_JAVA
AC_PATH_PROG([ANT], [ant])
AX_CHECK_ANT_VERSION($ANT, 1.7)
AC_SUBST(CLASSPATH)
AC_SUBST(ANT_FLAGS)
if test "x$JAVAC" != "x" && test "x$JAVAC" != "x" && test "x$ANT" != "x" ; then
have_java="yes"
fi
fi
AM_CONDITIONAL(WITH_JAVA, [test "$have_java" = "yes"])
AX_THRIFT_LIB(php, [PHP], yes)
if test "$with_php" = "yes"; then
AC_PATH_PROG([PHP], [php])
if test "x$PHP" != "x" && test "x$PHP" != "x:" ; then
have_php="yes"
fi
fi
AM_CONDITIONAL(WITH_PHP, [test "$have_php" = "yes"])
AX_THRIFT_LIB(python, [Python], yes)
if test "$with_python" = "yes"; then
AM_PATH_PYTHON(2.4,, :)
if test "x$PYTHON" != "x" && test "x$PYTHON" != "x:" ; then
have_python="yes"
fi
fi
AM_CONDITIONAL(WITH_PYTHON, [test "$have_python" = "yes"])
# Generates Makefile from Makefile.am. Modify when new subdirs are added.
# Change Makefile.am also to add subdirectly.
AC_CONFIG_FILES(Makefile cpp/Makefile py/Makefile)
# Check for headers
AC_CHECK_HEADERS([inttypes.h])
AC_CHECK_HEADERS([netinet/in.h])
############################################################################
# DO NOT TOUCH.
AC_SUBST(PRODUCT_MK)
AC_OUTPUT
#############################################################################
######### FINISH ############################################################
echo "EXTERNAL_PATH $EXTERNAL_PATH"
echo
echo "Building C++ Library ......... : $have_cpp"
echo "Building Java Library ........ : $have_java"
echo "Building Python Library ...... : $have_python"
echo "Building PHP Library ......... : $have_php"
#
# NOTES FOR USER
# Short cut to create conditional flags.
#enable_facebook="yes"
#AM_CONDITIONAL([FACEBOOK], [test "$enable_facebook" = yes])
#enable_hdfs="yes"
#AM_CONDITIONAL([HDFS], [test "$enable_hdfs" = yes])
# Enable options with --enable and --disable configurable.
#AC_MSG_CHECKING([whether to enable FACEBOOK])
#FACEBOOK=""
#AC_ARG_ENABLE([facebook],
# [ --enable-facebook Enable facebook.],
# [
# ENABLE_FACEBOOK=$enableval
# ],
# [
# ENABLE_FACEBOOK="no"
# ]
#)
#AM_CONDITIONAL([FACEBOOK], [test "$ENABLE_FACEBOOK" = yes])
#AC_MSG_RESULT($ENABLE_FACEBOOK)

View file

@ -0,0 +1,124 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include "FacebookBase.h"
using namespace facebook::fb303;
using apache::thrift::concurrency::Guard;
FacebookBase::FacebookBase(std::string name) :
name_(name) {
aliveSince_ = (int64_t) time(NULL);
}
inline void FacebookBase::getName(std::string& _return) {
_return = name_;
}
void FacebookBase::setOption(const std::string& key, const std::string& value) {
Guard g(optionsLock_);
options_[key] = value;
}
void FacebookBase::getOption(std::string& _return, const std::string& key) {
Guard g(optionsLock_);
_return = options_[key];
}
void FacebookBase::getOptions(std::map<std::string, std::string> & _return) {
Guard g(optionsLock_);
_return = options_;
}
int64_t FacebookBase::incrementCounter(const std::string& key, int64_t amount) {
counters_.acquireRead();
// if we didn't find the key, we need to write lock the whole map to create it
ReadWriteCounterMap::iterator it = counters_.find(key);
if (it == counters_.end()) {
counters_.release();
counters_.acquireWrite();
// we need to check again to make sure someone didn't create this key
// already while we released the lock
it = counters_.find(key);
if(it == counters_.end()){
counters_[key].value = amount;
counters_.release();
return amount;
}
}
it->second.acquireWrite();
int64_t count = it->second.value + amount;
it->second.value = count;
it->second.release();
counters_.release();
return count;
}
int64_t FacebookBase::setCounter(const std::string& key, int64_t value) {
counters_.acquireRead();
// if we didn't find the key, we need to write lock the whole map to create it
ReadWriteCounterMap::iterator it = counters_.find(key);
if (it == counters_.end()) {
counters_.release();
counters_.acquireWrite();
counters_[key].value = value;
counters_.release();
return value;
}
it->second.acquireWrite();
it->second.value = value;
it->second.release();
counters_.release();
return value;
}
void FacebookBase::getCounters(std::map<std::string, int64_t>& _return) {
// we need to lock the whole thing and actually build the map since we don't
// want our read/write structure to go over the wire
counters_.acquireRead();
for(ReadWriteCounterMap::iterator it = counters_.begin();
it != counters_.end(); ++it)
{
_return[it->first] = it->second.value;
}
counters_.release();
}
int64_t FacebookBase::getCounter(const std::string& key) {
int64_t rv = 0;
counters_.acquireRead();
ReadWriteCounterMap::iterator it = counters_.find(key);
if (it != counters_.end()) {
it->second.acquireRead();
rv = it->second.value;
it->second.release();
}
counters_.release();
return rv;
}
inline int64_t FacebookBase::aliveSince() {
return aliveSince_;
}

View file

@ -0,0 +1,103 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#ifndef _FACEBOOK_TB303_FACEBOOKBASE_H_
#define _FACEBOOK_TB303_FACEBOOKBASE_H_ 1
#include "FacebookService.h"
#include <thrift/server/TServer.h>
#include <thrift/concurrency/Mutex.h>
#include <time.h>
#include <string>
#include <map>
namespace facebook { namespace fb303 {
using apache::thrift::concurrency::Mutex;
using apache::thrift::concurrency::ReadWriteMutex;
using apache::thrift::server::TServer;
struct ReadWriteInt : ReadWriteMutex {int64_t value;};
struct ReadWriteCounterMap : ReadWriteMutex,
std::map<std::string, ReadWriteInt> {};
/**
* Base Facebook service implementation in C++.
*
*/
class FacebookBase : virtual public FacebookServiceIf {
protected:
FacebookBase(std::string name);
virtual ~FacebookBase() {}
public:
void getName(std::string& _return);
virtual void getVersion(std::string& _return) { _return = ""; }
virtual fb_status getStatus() = 0;
virtual void getStatusDetails(std::string& _return) { _return = ""; }
void setOption(const std::string& key, const std::string& value);
void getOption(std::string& _return, const std::string& key);
void getOptions(std::map<std::string, std::string> & _return);
int64_t aliveSince();
virtual void reinitialize() {}
virtual void shutdown() {
if (server_.get() != NULL) {
server_->stop();
}
}
int64_t incrementCounter(const std::string& key, int64_t amount = 1);
int64_t setCounter(const std::string& key, int64_t value);
void getCounters(std::map<std::string, int64_t>& _return);
int64_t getCounter(const std::string& key);
/**
* Set server handle for shutdown method
*/
void setServer(boost::shared_ptr<TServer> server) {
server_ = server;
}
void getCpuProfile(std::string& _return, int32_t durSecs) { _return = ""; }
private:
std::string name_;
int64_t aliveSince_;
std::map<std::string, std::string> options_;
Mutex optionsLock_;
ReadWriteCounterMap counters_;
boost::shared_ptr<TServer> server_;
};
}} // facebook::tb303
#endif // _FACEBOOK_TB303_FACEBOOKBASE_H_

View file

@ -0,0 +1,84 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
@GLOBAL_HEADER_MK@
@PRODUCT_MK@
# User specified path variables set in configure.ac.
# thrift_home
#
THRIFT = $(thrift_home)/bin/thrift
# User defined conditionals and conditonal statements set up in configure.ac.
if DEBUG
DEBUG_CPPFLAGS = -DDEBUG_TIMING
endif
# Set common flags recognized by automake.
# DO NOT USE CPPFLAGS, CXXFLAGS, CFLAGS, LDFLAGS here! Set in configure.ac and|or override on command line.
# USE flags AM_CXXFLAGS, AM_CFLAGS, AM_CPPFLAGS, AM_LDFLAGS, LDADD in this section.
AM_CPPFLAGS = -I..
AM_CPPFLAGS += -Igen-cpp
AM_CPPFLAGS += -I$(thrift_home)/include/thrift
AM_CPPFLAGS += $(BOOST_CPPFLAGS)
AM_CPPFLAGS += $(FB_CPPFLAGS) $(DEBUG_CPPFLAGS)
# GENERATE BUILD RULES
# Set Program/library specific flags recognized by automake.
# Use <progname|libname>_<FLAG> to set prog / lib specific flag s
# foo_CXXFLAGS foo_CPPFLAGS foo_LDFLAGS foo_LDADD
fb303_lib = gen-cpp/FacebookService.cpp gen-cpp/fb303_constants.cpp gen-cpp/fb303_types.cpp FacebookBase.cpp ServiceTracker.cpp
# Static -- multiple libraries can be defined
if STATIC
lib_LIBRARIES = libfb303.a
libfb303_a_SOURCES = $(fb303_lib)
INTERNAL_LIBS = libfb303.a
endif
# Shared -- multiple libraries can be defined
if SHARED
shareddir = $(prefix)/lib
shared_PROGRAMS = libfb303.so
libfb303_so_SOURCES = $(fb303_lib)
libfb303_so_CXXFLAGS = $(SHARED_CXXFLAGS)
libfb303_so_LDFLAGS = $(SHARED_LDFLAGS)
INTERNAL_LIBS = libfb303.so
endif
# Set up Thrift specific activity here.
# We assume that a <name>+types.cpp will always be built from <name>.thrift.
$(eval $(call thrift_template,.,../if/fb303.thrift,-I $(thrift_home)/share --gen cpp:pure_enums ))
include_fb303dir = $(includedir)/thrift/fb303
include_fb303_HEADERS = FacebookBase.h ServiceTracker.h gen-cpp/FacebookService.h gen-cpp/fb303_constants.h gen-cpp/fb303_types.h
include_fb303ifdir = $(prefix)/share/fb303/if
include_fb303if_HEADERS = ../if/fb303.thrift
BUILT_SOURCES = thriftstyle
# Add to pre-existing target clean
clean-local: clean-common
@GLOBAL_FOOTER_MK@

View file

@ -0,0 +1,481 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include <sys/time.h>
#include "FacebookBase.h"
#include "ServiceTracker.h"
#include <thrift/concurrency/ThreadManager.h>
using namespace std;
using namespace facebook::fb303;
using namespace apache::thrift::concurrency;
uint64_t ServiceTracker::CHECKPOINT_MINIMUM_INTERVAL_SECONDS = 60;
int ServiceTracker::LOG_LEVEL = 5;
ServiceTracker::ServiceTracker(facebook::fb303::FacebookBase *handler,
void (*logMethod)(int, const string &),
bool featureCheckpoint,
bool featureStatusCheck,
bool featureThreadCheck,
Stopwatch::Unit stopwatchUnit)
: handler_(handler), logMethod_(logMethod),
featureCheckpoint_(featureCheckpoint),
featureStatusCheck_(featureStatusCheck),
featureThreadCheck_(featureThreadCheck),
stopwatchUnit_(stopwatchUnit),
checkpointServices_(0)
{
if (featureCheckpoint_) {
time_t now = time(NULL);
checkpointTime_ = now;
} else {
checkpointTime_ = 0;
}
}
/**
* Registers the beginning of a "service method": basically, any of
* the implementations of Thrift remote procedure calls that a
* FacebookBase handler is handling. Controls concurrent
* services and reports statistics (via log and via fb303 counters).
* Throws an exception if the server is not ready to handle service
* methods yet.
*
* note: The relationship between startService() and finishService()
* is currently defined so that a call to finishService() should only
* be matched to this call to startService() if this method returns
* without exception. It wouldn't be a problem to implement things
* the other way, so that *every* start needed a finish, but this
* convention was chosen to match the way an object's constructor and
* destructor work together, i.e. to work well with ServiceMethod
* objects.
*
* @param const ServiceMethod &serviceMethod A reference to the ServiceMethod
* object instantiated at the start
* of the service method.
*/
void
ServiceTracker::startService(const ServiceMethod &serviceMethod)
{
// note: serviceMethod.timer_ automatically starts at construction.
// log service start
logMethod_(5, serviceMethod.signature_);
// check handler ready
if (featureStatusCheck_ && !serviceMethod.featureLogOnly_) {
// note: Throwing exceptions before counting statistics. See note
// in method header.
// note: A STOPPING server is not accepting new connections, but it
// is still handling any already-connected threads -- so from the
// service method's point of view, a status of STOPPING is a green
// light.
facebook::fb303::fb_status status = handler_->getStatus();
if (status != facebook::fb303::ALIVE
&& status != facebook::fb303::STOPPING) {
if (status == facebook::fb303::STARTING) {
throw ServiceException("Server starting up; please try again later");
} else {
throw ServiceException("Server not alive; please try again later");
}
}
}
// check server threads
if (featureThreadCheck_ && !serviceMethod.featureLogOnly_) {
// note: Might want to put these messages in reportCheckpoint() if
// log is getting spammed.
if (threadManager_ != NULL) {
size_t idle_count = threadManager_->idleWorkerCount();
if (idle_count == 0) {
stringstream message;
message << "service " << serviceMethod.signature_
<< ": all threads (" << threadManager_->workerCount()
<< ") in use";
logMethod_(3, message.str());
}
}
}
}
/**
* Logs a significant step in the middle of a "service method"; see
* startService.
*
* @param const ServiceMethod &serviceMethod A reference to the ServiceMethod
* object instantiated at the start
* of the service method.
* @return int64_t Elapsed units (see stopwatchUnit_) since ServiceMethod
* instantiation.
*/
int64_t
ServiceTracker::stepService(const ServiceMethod &serviceMethod,
const string &stepName)
{
stringstream message;
string elapsed_label;
int64_t elapsed = serviceMethod.timer_.elapsedUnits(stopwatchUnit_,
&elapsed_label);
message << serviceMethod.signature_
<< ' ' << stepName
<< " [" << elapsed_label << ']';
logMethod_(5, message.str());
return elapsed;
}
/**
* Registers the end of a "service method"; see startService().
*
* @param const ServiceMethod &serviceMethod A reference to the ServiceMethod
* object instantiated at the start
* of the service method.
*/
void
ServiceTracker::finishService(const ServiceMethod &serviceMethod)
{
// log end of service
stringstream message;
string duration_label;
int64_t duration = serviceMethod.timer_.elapsedUnits(stopwatchUnit_,
&duration_label);
message << serviceMethod.signature_
<< " finish [" << duration_label << ']';
logMethod_(5, message.str());
// count, record, and maybe report service statistics
if (!serviceMethod.featureLogOnly_) {
if (!featureCheckpoint_) {
// lifetime counters
// (note: No need to lock statisticsMutex_ if not doing checkpoint;
// FacebookService::incrementCounter() is already thread-safe.)
handler_->incrementCounter("lifetime_services");
} else {
statisticsMutex_.lock();
// note: No exceptions expected from this code block. Wrap in a try
// just to be safe.
try {
// lifetime counters
// note: Good to synchronize this with the increment of
// checkpoint services, even though incrementCounter() is
// already thread-safe, for the sake of checkpoint reporting
// consistency (i.e. since the last checkpoint,
// lifetime_services has incremented by checkpointServices_).
handler_->incrementCounter("lifetime_services");
// checkpoint counters
checkpointServices_++;
checkpointDuration_ += duration;
// per-service timing
// note kjv: According to my tests it is very slightly faster to
// call insert() once (and detect not-found) than calling find()
// and then maybe insert (if not-found). However, the difference
// is tiny for small maps like this one, and the code for the
// faster solution is slightly less readable. Also, I wonder if
// the instantiation of the (often unused) pair to insert makes
// the first algorithm slower after all.
map<string, pair<uint64_t, uint64_t> >::iterator iter;
iter = checkpointServiceDuration_.find(serviceMethod.name_);
if (iter != checkpointServiceDuration_.end()) {
iter->second.first++;
iter->second.second += duration;
} else {
checkpointServiceDuration_.insert(make_pair(serviceMethod.name_,
make_pair(1, duration)));
}
// maybe report checkpoint
// note: ...if it's been long enough since the last report.
time_t now = time(NULL);
uint64_t check_interval = now - checkpointTime_;
if (check_interval >= CHECKPOINT_MINIMUM_INTERVAL_SECONDS) {
reportCheckpoint();
}
} catch (...) {
statisticsMutex_.unlock();
throw;
}
statisticsMutex_.unlock();
}
}
}
/**
* Logs some statistics gathered since the last call to this method.
*
* note: Thread race conditions on this method could cause
* misreporting and/or undefined behavior; the caller must protect
* uses of the object variables (and calls to this method) with a
* mutex.
*
*/
void
ServiceTracker::reportCheckpoint()
{
time_t now = time(NULL);
uint64_t check_count = checkpointServices_;
uint64_t check_interval = now - checkpointTime_;
uint64_t check_duration = checkpointDuration_;
// export counters for timing of service methods (by service name)
handler_->setCounter("checkpoint_time", check_interval);
map<string, pair<uint64_t, uint64_t> >::iterator iter;
uint64_t count;
for (iter = checkpointServiceDuration_.begin();
iter != checkpointServiceDuration_.end();
++iter) {
count = iter->second.first;
handler_->setCounter(string("checkpoint_count_") + iter->first, count);
if (count == 0) {
handler_->setCounter(string("checkpoint_speed_") + iter->first,
0);
} else {
handler_->setCounter(string("checkpoint_speed_") + iter->first,
iter->second.second / count);
}
}
// reset checkpoint variables
// note: Clearing the map while other threads are using it might
// cause undefined behavior.
checkpointServiceDuration_.clear();
checkpointTime_ = now;
checkpointServices_ = 0;
checkpointDuration_ = 0;
// get lifetime variables
uint64_t life_count = handler_->getCounter("lifetime_services");
uint64_t life_interval = now - handler_->aliveSince();
// log checkpoint
stringstream message;
message << "checkpoint_time:" << check_interval
<< " checkpoint_services:" << check_count
<< " checkpoint_speed_sum:" << check_duration
<< " lifetime_time:" << life_interval
<< " lifetime_services:" << life_count;
if (featureThreadCheck_ && threadManager_ != NULL) {
size_t worker_count = threadManager_->workerCount();
size_t idle_count = threadManager_->idleWorkerCount();
message << " total_workers:" << worker_count
<< " active_workers:" << (worker_count - idle_count);
}
logMethod_(4, message.str());
}
/**
* Remembers the thread manager used in the server, for monitoring thread
* activity.
*
* @param shared_ptr<ThreadManager> threadManager The server's thread manager.
*/
void
ServiceTracker::setThreadManager(boost::shared_ptr<ThreadManager>
threadManager)
{
threadManager_ = threadManager;
}
/**
* Logs messages to stdout; the passed message will be logged if the
* passed level is less than or equal to LOG_LEVEL.
*
* This is the default logging method used by the ServiceTracker. An
* alternate logging method (that accepts the same parameters) may be
* specified to the constructor.
*
* @param int level A level associated with the message: higher levels
* are used to indicate higher levels of detail.
* @param string message The message to log.
*/
void
ServiceTracker::defaultLogMethod(int level, const string &message)
{
if (level <= LOG_LEVEL) {
string level_string;
time_t now = time(NULL);
char now_pretty[26];
ctime_r(&now, now_pretty);
now_pretty[24] = '\0';
switch (level) {
case 1:
level_string = "CRITICAL";
break;
case 2:
level_string = "ERROR";
break;
case 3:
level_string = "WARNING";
break;
case 5:
level_string = "DEBUG";
break;
case 4:
default:
level_string = "INFO";
break;
}
cout << '[' << level_string << "] [" << now_pretty << "] "
<< message << endl;
}
}
/**
* Creates a Stopwatch, which can report the time elapsed since its
* creation.
*
*/
Stopwatch::Stopwatch()
{
gettimeofday(&startTime_, NULL);
}
void
Stopwatch::reset()
{
gettimeofday(&startTime_, NULL);
}
uint64_t
Stopwatch::elapsedUnits(Stopwatch::Unit unit, string *label) const
{
timeval now_time;
gettimeofday(&now_time, NULL);
time_t duration_secs = now_time.tv_sec - startTime_.tv_sec;
uint64_t duration_units;
switch (unit) {
case UNIT_SECONDS:
duration_units = duration_secs
+ (now_time.tv_usec - startTime_.tv_usec + 500000) / 1000000;
if (NULL != label) {
stringstream ss_label;
ss_label << duration_units << " secs";
label->assign(ss_label.str());
}
break;
case UNIT_MICROSECONDS:
duration_units = duration_secs * 1000000
+ now_time.tv_usec - startTime_.tv_usec;
if (NULL != label) {
stringstream ss_label;
ss_label << duration_units << " us";
label->assign(ss_label.str());
}
break;
case UNIT_MILLISECONDS:
default:
duration_units = duration_secs * 1000
+ (now_time.tv_usec - startTime_.tv_usec + 500) / 1000;
if (NULL != label) {
stringstream ss_label;
ss_label << duration_units << " ms";
label->assign(ss_label.str());
}
break;
}
return duration_units;
}
/**
* Creates a ServiceMethod, used for tracking a single service method
* invocation (via the ServiceTracker). The passed name of the
* ServiceMethod is used to group statistics (e.g. counts and durations)
* for similar invocations; the passed signature is used to uniquely
* identify the particular invocation in the log.
*
* note: A version of this constructor is provided that automatically
* forms a signature the name and a passed numeric id. Silly, sure,
* but commonly used, since it often saves the caller a line or two of
* code.
*
* @param ServiceTracker *tracker The service tracker that will track this
* ServiceMethod.
* @param const string &name The service method name (usually independent
* of service method parameters).
* @param const string &signature A signature uniquely identifying the method
* invocation (usually name plus parameters).
*/
ServiceMethod::ServiceMethod(ServiceTracker *tracker,
const string &name,
const string &signature,
bool featureLogOnly)
: tracker_(tracker), name_(name), signature_(signature),
featureLogOnly_(featureLogOnly)
{
// note: timer_ automatically starts at construction.
// invoke tracker to start service
// note: Might throw. If it throws, then this object's destructor
// won't be called, which is according to plan: finishService() is
// only supposed to be matched to startService() if startService()
// returns without error.
tracker_->startService(*this);
}
ServiceMethod::ServiceMethod(ServiceTracker *tracker,
const string &name,
uint64_t id,
bool featureLogOnly)
: tracker_(tracker), name_(name), featureLogOnly_(featureLogOnly)
{
// note: timer_ automatically starts at construction.
stringstream ss_signature;
ss_signature << name << " (" << id << ')';
signature_ = ss_signature.str();
// invoke tracker to start service
// note: Might throw. If it throws, then this object's destructor
// won't be called, which is according to plan: finishService() is
// only supposed to be matched to startService() if startService()
// returns without error.
tracker_->startService(*this);
}
ServiceMethod::~ServiceMethod()
{
// invoke tracker to finish service
// note: Not expecting an exception from this code, but
// finishService() might conceivably throw an out-of-memory
// exception.
try {
tracker_->finishService(*this);
} catch (...) {
// don't throw
}
}
uint64_t
ServiceMethod::step(const std::string &stepName)
{
return tracker_->stepService(*this, stepName);
}

View file

@ -0,0 +1,215 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
/**
* ServiceTracker is a utility class for logging and timing service
* calls to a fb303 Thrift server. Currently, ServiceTracker offers
* the following features:
*
* . Logging of service method start, end (and duration), and
* optional steps in between.
*
* . Automatic check of server status via fb303::getStatus()
* with a ServiceException thrown if server not alive
* (at method start).
*
* . A periodic logged checkpoint reporting lifetime time, lifetime
* service count, and per-method statistics since the last checkpoint
* time (at method finish).
*
* . Export of fb303 counters for lifetime and checkpoint statistics
* (at method finish).
*
* . For TThreadPoolServers, a logged warning when all server threads
* are busy (at method start). (Must call setThreadManager() after
* ServiceTracker instantiation for this feature to be enabled.)
*
* Individual features may be enabled or disabled by arguments to the
* constructor. The constructor also accepts a pointer to a logging
* method -- if no pointer is passed, the tracker will log to stdout.
*
* ServiceTracker defines private methods for service start, finish,
* and step, which are designed to be accessed by instantiating a
* friend ServiceMethod object, as in the following example:
*
* #include <ServiceTracker.h>
* class MyServiceHandler : virtual public MyServiceIf,
* public facebook::fb303::FacebookBase
* {
* public:
* MyServiceHandler::MyServiceHandler() : mServiceTracker(this) {}
* void MyServiceHandler::myServiceMethod(int userId) {
* // note: Instantiating a ServiceMethod object starts a timer
* // and tells the ServiceTracker to log the start. Might throw
* // a ServiceException.
* ServiceMethod serviceMethod(&mServiceTracker,
* "myServiceMethod",
* userId);
* ...
* // note: Calling the step method tells the ServiceTracker to
* // log the step, with a time elapsed since start.
* serviceMethod.step("post parsing, begin processing");
* ...
* // note: When the ServiceMethod object goes out of scope, the
* // ServiceTracker will log the total elapsed time of the method.
* }
* ...
* private:
* ServiceTracker mServiceTracker;
* }
*
* The step() method call is optional; the startService() and
* finishService() methods are handled by the object's constructor and
* destructor.
*
* The ServiceTracker is (intended to be) thread-safe.
*
* Future:
*
* . Come up with something better for logging than passing a
* function pointer to the constructor.
*
* . Add methods for tracking errors from service methods, e.g.
* ServiceTracker::reportService().
*/
#ifndef SERVICETRACKER_H
#define SERVICETRACKER_H
#include <iostream>
#include <string>
#include <sstream>
#include <exception>
#include <map>
#include <boost/shared_ptr.hpp>
#include <thrift/concurrency/Mutex.h>
namespace apache { namespace thrift { namespace concurrency {
class ThreadManager;
}}}
namespace facebook { namespace fb303 {
class FacebookBase;
class ServiceMethod;
class Stopwatch
{
public:
enum Unit { UNIT_SECONDS, UNIT_MILLISECONDS, UNIT_MICROSECONDS };
Stopwatch();
uint64_t elapsedUnits(Unit unit, std::string *label = NULL) const;
void reset();
private:
timeval startTime_;
};
class ServiceTracker
{
friend class ServiceMethod;
public:
static uint64_t CHECKPOINT_MINIMUM_INTERVAL_SECONDS;
static int LOG_LEVEL;
ServiceTracker(facebook::fb303::FacebookBase *handler,
void (*logMethod)(int, const std::string &)
= &ServiceTracker::defaultLogMethod,
bool featureCheckpoint = true,
bool featureStatusCheck = true,
bool featureThreadCheck = true,
Stopwatch::Unit stopwatchUnit
= Stopwatch::UNIT_MILLISECONDS);
void setThreadManager(boost::shared_ptr<apache::thrift::concurrency::ThreadManager> threadManager);
private:
facebook::fb303::FacebookBase *handler_;
void (*logMethod_)(int, const std::string &);
boost::shared_ptr<apache::thrift::concurrency::ThreadManager> threadManager_;
bool featureCheckpoint_;
bool featureStatusCheck_;
bool featureThreadCheck_;
Stopwatch::Unit stopwatchUnit_;
apache::thrift::concurrency::Mutex statisticsMutex_;
time_t checkpointTime_;
uint64_t checkpointServices_;
uint64_t checkpointDuration_;
std::map<std::string, std::pair<uint64_t, uint64_t> > checkpointServiceDuration_;
void startService(const ServiceMethod &serviceMethod);
int64_t stepService(const ServiceMethod &serviceMethod,
const std::string &stepName);
void finishService(const ServiceMethod &serviceMethod);
void reportCheckpoint();
static void defaultLogMethod(int level, const std::string &message);
};
class ServiceMethod
{
friend class ServiceTracker;
public:
ServiceMethod(ServiceTracker *tracker,
const std::string &name,
const std::string &signature,
bool featureLogOnly = false);
ServiceMethod(ServiceTracker *tracker,
const std::string &name,
uint64_t id,
bool featureLogOnly = false);
~ServiceMethod();
uint64_t step(const std::string &stepName);
private:
ServiceTracker *tracker_;
std::string name_;
std::string signature_;
bool featureLogOnly_;
Stopwatch timer_;
};
class ServiceException : public std::exception
{
public:
explicit ServiceException(const std::string &message, int code = 0)
: message_(message), code_(code) {}
~ServiceException() throw() {}
virtual const char *what() const throw() { return message_.c_str(); }
int code() const throw() { return code_; }
private:
std::string message_;
int code_;
};
}} // facebook::fb303
#endif

View file

@ -0,0 +1,21 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
thriftstyle : $(XBUILT_SOURCES)

View file

@ -0,0 +1,38 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
#define thrift_template
# $(1) : $(2)
# $$(THRIFT) $(3) $(4) $(5) $(6) $(7) $(8) $$<
#endef
define thrift_template
XTARGET := $(shell perl -e '@val = split("\/","$(2)"); $$last = pop(@val);split("\\.",$$last);print "$(1)/"."gen-cpp/"."@_[0]"."_types.cpp\n"' )
ifneq ($$(XBUILT_SOURCES),)
XBUILT_SOURCES := $$(XBUILT_SOURCES) $$(XTARGET)
else
XBUILT_SOURCES := $$(XTARGET)
endif
$$(XTARGET) : $(2)
$$(THRIFT) -o $1 $3 $$<
endef
clean-common:
rm -rf gen-*

View file

@ -0,0 +1,112 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
/**
* fb303.thrift
*/
namespace java com.facebook.fb303
namespace cpp facebook.fb303
namespace perl Facebook.FB303
/**
* Common status reporting mechanism across all services
*/
enum fb_status {
DEAD = 0,
STARTING = 1,
ALIVE = 2,
STOPPING = 3,
STOPPED = 4,
WARNING = 5,
}
/**
* Standard base service
*/
service FacebookService {
/**
* Returns a descriptive name of the service
*/
string getName(),
/**
* Returns the version of the service
*/
string getVersion(),
/**
* Gets the status of this service
*/
fb_status getStatus(),
/**
* User friendly description of status, such as why the service is in
* the dead or warning state, or what is being started or stopped.
*/
string getStatusDetails(),
/**
* Gets the counters for this service
*/
map<string, i64> getCounters(),
/**
* Gets the value of a single counter
*/
i64 getCounter(1: string key),
/**
* Sets an option
*/
void setOption(1: string key, 2: string value),
/**
* Gets an option
*/
string getOption(1: string key),
/**
* Gets all options
*/
map<string, string> getOptions(),
/**
* Returns a CPU profile over the given time interval (client and server
* must agree on the profile format).
*/
string getCpuProfile(1: i32 profileDurationInSec),
/**
* Returns the unix time that the server has been running since
*/
i64 aliveSince(),
/**
* Tell the server to reload its configuration, reopen log files, etc
*/
oneway void reinitialize(),
/**
* Suggest a shutdown to the server
*/
oneway void shutdown(),
}

195
vendor/git.apache.org/thrift.git/contrib/fb303/java/build.xml generated vendored Executable file
View file

@ -0,0 +1,195 @@
<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.
-->
<project name="libfb303" default="dist" basedir="."
xmlns:artifact="antlib:org.apache.maven.artifact.ant">
<!-- project wide settings. All directories relative to basedir -->
<property name="thrift.root" location="${basedir}/../../../"/>
<property name="fb303.artifactid" value="libfb303"/>
<property name="interface.dir" value="${basedir}/../if"/>
<property name="thrift.java.dir" location="${thrift.root}/lib/java"/>
<property name="build.tools.dir" location="${thrift.java.dir}/build/tools/"/>
<property name="thrift_compiler" value="${thrift.root}/compiler/cpp/thrift"/>
<!-- inherit from the java build file for version and other properties -->
<property file="${thrift.java.dir}/build.properties" />
<property environment="env"/>
<condition property="version" value="${thrift.version}">
<isset property="release"/>
</condition>
<property name="version" value="${thrift.version}-snapshot"/>
<property name="fb303.final.name" value="${fb303.artifactid}-${version}"/>
<property name="thrift.java.libthrift" value="${thrift.java.dir}/build/libthrift-${version}.jar"/>
<property name="src" value="${basedir}/src"/>
<property name="gen" value="${basedir}/gen-java"/>
<property name="build.dir" value="${basedir}/build"/>
<property name="build.lib.dir" value="${build.dir}/lib"/>
<property name="build.classes.dir" value="${build.dir}/classes"/>
<property name="fb303.jar.file" location="${build.dir}/${fb303.final.name}.jar"/>
<property name="fb303.pom.xml" location="${build.dir}/${fb303.final.name}.pom"/>
<target name="init" depends="setup.init,mvn.init" unless="init.finished">
<property name="init.finished" value="true"/>
</target>
<target name="setup.init">
<tstamp/>
<mkdir dir="${build.dir}"/>
<mkdir dir="${build.classes.dir}"/>
<mkdir dir="${build.lib.dir}"/>
</target>
<!-- generate fb303 thrift code -->
<target name="generate">
<echo message="generating thrift fb303 files"/>
<exec executable="${thrift_compiler}" failonerror="true">
<arg line="--gen java -o ${basedir} ${interface.dir}/fb303.thrift"/>
</exec>
</target>
<!-- compile the base and thrift generated code and jar them -->
<target name="dist" depends="init,generate">
<echo message="Building ${fb303.final.name}.jar"/>
<javac destdir="${build.classes.dir}" debug="on">
<classpath>
<pathelement location="${thrift.java.libthrift}"/>
<fileset dir="${thrift.root}/lib/java/build/lib">
<include name="*.jar"/>
</fileset>
</classpath>
<src path="${src}"/>
<src path="${gen}"/>
<include name="**/*.java"/>
</javac>
<jar jarfile="${build.dir}/${fb303.final.name}.jar" basedir="${build.classes.dir}">
</jar>
</target>
<!-- copy the build jar to the distribution library directory -->
<target name="install" depends="dist">
<copy todir="${install.path}">
<fileset dir="${build.lib.dir}" includes="*.jar"/>
<fileset dir="${build.lib.dir}" includes="${fb303.final.name}.jar"/>
</copy>
</target>
<target name="clean">
<delete dir="${build.dir}"/>
<delete dir="${gen}"/>
</target>
<target name="mvn.ant.tasks.download" depends="setup.init,mvn.ant.tasks.check" unless="mvn.ant.tasks.found">
<get src="${mvn.ant.task.url}/${mvn.ant.task.jar}" dest="${build.tools.dir}/${mvn.ant.task.jar}" usetimestamp="true"/>
</target>
<target name="mvn.ant.tasks.check">
<condition property="mvn.ant.tasks.found">
<typefound uri="antlib:org.apache.maven.artifact.ant" name="artifact"/>
</condition>
</target>
<target name="mvn.init" depends="mvn.ant.tasks.download" unless="mvn.finished">
<echo message="${mvn.ant.task.jar}"/>
<!-- Download mvn ant tasks, download dependencies, and setup pom file -->
<typedef uri="antlib:org.apache.maven.artifact.ant" classpath="${build.tools.dir}/${mvn.ant.task.jar}"/>
<!-- remote repositories used to download dependencies from -->
<artifact:remoteRepository id="central" url="${mvn.repo}"/>
<artifact:remoteRepository id="apache" url="${apache.repo}"/>
<!-- Pom file information -->
<artifact:pom id="pom"
groupId="${thrift.groupid}"
artifactId="${fb303.artifactid}"
version="${version}"
url="http://thrift.apache.org"
name="Apache Thrift"
description="Thrift is a software framework for scalable cross-language services development."
packaging="pom"
>
<remoteRepository refid="central"/>
<remoteRepository refid="apache"/>
<license name="The Apache Software License, Version 2.0" url="${license}"/>
<scm connection="scm:git:https://git-wip-us.apache.org/repos/asf/thrift.git"
developerConnection="scm:git:https://git-wip-us.apache.org/repos/asf/thrift.git"
url="https://git-wip-us.apache.org/repos/asf?p=thrift.git"
/>
<!-- Thrift Developers -->
<developer id="mcslee" name="Mark Slee"/>
<developer id="dreiss" name="David Reiss"/>
<developer id="aditya" name="Aditya Agarwal"/>
<developer id="marck" name="Marc Kwiatkowski"/>
<developer id="jwang" name="James Wang"/>
<developer id="cpiro" name="Chris Piro"/>
<developer id="bmaurer" name="Ben Maurer"/>
<developer id="kclark" name="Kevin Clark"/>
<developer id="jake" name="Jake Luciani"/>
<developer id="bryanduxbury" name="Bryan Duxbury"/>
<developer id="esteve" name="Esteve Fernandez"/>
<developer id="todd" name="Todd Lipcon"/>
<developer id="geechorama" name="Andrew McGeachie"/>
<developer id="molinaro" name="Anthony Molinaro"/>
<developer id="roger" name="Roger Meier"/>
<developer id="jfarrell" name="Jake Farrell"/>
<developer id="jensg" name="Jens Geyer"/>
<developer id="carl" name="Carl Yeksigian"/>
<!-- Thrift dependencies list -->
<dependency groupId="org.apache.thrift" artifactId="libthrift" version="${version}"/>
</artifact:pom>
<!-- Generate the pom file -->
<artifact:writepom pomRefId="pom" file="${fb303.pom.xml}"/>
<property name="mvn.finished" value="true"/>
</target>
<macrodef name="signAndDeploy">
<!-- Sign and deploy jars to apache repo -->
<attribute name="file"/>
<attribute name="classifier" default=""/>
<attribute name="packaging" default="jar"/>
<attribute name="pom" default=""/>
<sequential>
<artifact:mvn fork="true">
<arg value="org.apache.maven.plugins:maven-gpg-plugin:1.1:sign-and-deploy-file"/>
<arg value="-DrepositoryId=${maven-repository-id}"/>
<arg value="-Durl=${maven-repository-url}"/>
<arg value="-DpomFile=@{pom}"/>
<arg value="-Dfile=@{file}"/>
<arg value="-Dclassifier=@{classifier}"/>
<arg value="-Dpackaging=@{packaging}"/>
<arg value="-Pgpg"/>
</artifact:mvn>
</sequential>
</macrodef>
<target name="publish" depends="clean,dist">
<!-- Compile, packages and then send release to apache maven repo -->
<!-- run with: ant -Drelease=true publish-->
<signAndDeploy file="${fb303.pom.xml}" packaging="pom" classifier="" pom="${fb303.pom.xml}"/>
<signAndDeploy file="${fb303.jar.file}" packaging="jar" classifier="" pom="${fb303.pom.xml}"/>
</target>
</project>

View file

@ -0,0 +1,114 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 com.facebook.fb303;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
public abstract class FacebookBase implements FacebookService.Iface {
private String name_;
private long alive_;
private final ConcurrentHashMap<String,Long> counters_ =
new ConcurrentHashMap<String, Long>();
private final ConcurrentHashMap<String,String> options_ =
new ConcurrentHashMap<String, String>();
protected FacebookBase(String name) {
name_ = name;
alive_ = System.currentTimeMillis() / 1000;
}
public String getName() {
return name_;
}
public abstract fb_status getStatus();
public String getStatusDetails() {
return "";
}
public void deleteCounter(String key) {
counters_.remove(key);
}
public void resetCounter(String key) {
counters_.put(key, 0L);
}
public long incrementCounter(String key) {
long val = getCounter(key) + 1;
counters_.put(key, val);
return val;
}
public long incrementCounter(String key, long increment) {
long val = getCounter(key) + increment;
counters_.put(key, val);
return val;
}
public long setCounter(String key, long value) {
counters_.put(key, value);
return value;
}
public AbstractMap<String,Long> getCounters() {
return counters_;
}
public long getCounter(String key) {
Long val = counters_.get(key);
if (val == null) {
return 0;
}
return val.longValue();
}
public void setOption(String key, String value) {
options_.put(key, value);
}
public String getOption(String key) {
return options_.get(key);
}
public AbstractMap<String,String> getOptions() {
return options_;
}
public long aliveSince() {
return alive_;
}
public String getCpuProfile() {
return "";
}
public void reinitialize() {}
public void shutdown() {}
}

View file

@ -0,0 +1,89 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
/**
* Abstract Class providing null implementation for FacebookService
* methods.
*/
class FacebookBase implements FacebookServiceIf {
protected $name_ = '';
public function __construct($name) {
$this->name_ = $name;
}
public function getName() {
return $this->name_;
}
public function getVersion() {
return '';
}
public function getStatus() {
return null;
}
public function getStatusDetails() {
return '';
}
public function getCounters() {
return array();
}
public function getCounter($key) {
return null;
}
public function setOption($key, $value) {
return;
}
public function getOption($key) {
return '';
}
public function getOptions() {
return array();
}
public function aliveSince() {
return 0;
}
public function getCpuProfile($duration) {
return '';
}
public function getLimitedReflection() {
return array();
}
public function reinitialize() {
return;
}
public function shutdown() {
return;
}
}

View file

@ -0,0 +1,44 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
DESTDIR ?= /
EXTRA_DIST = setup.py src
all:
all-local:
$(thrift_home)/bin/thrift --gen py $(top_srcdir)/if/fb303.thrift
mv gen-py/fb303/* fb303
$(PYTHON) setup.py build
# We're ignoring prefix here because site-packages seems to be
# the equivalent of /usr/local/lib in Python land.
# Old version (can't put inline because it's not portable).
#$(PYTHON) setup.py install --prefix=$(prefix) --root=$(DESTDIR) $(PYTHON_SETUPUTIL_ARGS)
install-exec-hook:
$(PYTHON) setup.py install --root=$(DESTDIR) --prefix=$(PY_PREFIX) $(PYTHON_SETUPUTIL_ARGS)
clean: clean-local
clean-local:
$(RM) -r build
check-local: all

View file

@ -0,0 +1,83 @@
#!/usr/bin/env python
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
import time
import FacebookService
import thrift.reflection.limited
from ttypes import fb_status
class FacebookBase(FacebookService.Iface):
def __init__(self, name):
self.name = name
self.alive = int(time.time())
self.counters = {}
def getName(self, ):
return self.name
def getVersion(self, ):
return ''
def getStatus(self, ):
return fb_status.ALIVE
def getCounters(self):
return self.counters
def resetCounter(self, key):
self.counters[key] = 0
def getCounter(self, key):
if self.counters.has_key(key):
return self.counters[key]
return 0
def incrementCounter(self, key):
self.counters[key] = self.getCounter(key) + 1
def setOption(self, key, value):
pass
def getOption(self, key):
return ""
def getOptions(self):
return {}
def getOptions(self):
return {}
def aliveSince(self):
return self.alive
def getCpuProfile(self, duration):
return ""
def getLimitedReflection(self):
return thrift.reflection.limited.Service()
def reinitialize(self):
pass
def shutdown(self):
pass

View file

@ -0,0 +1,20 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
__all__ = ['fb303_simple_mgmt']

View file

@ -0,0 +1,194 @@
#!/usr/bin/env python
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
import sys
import os
from optparse import OptionParser
from thrift.Thrift import *
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from fb303 import *
from fb303.ttypes import *
def service_ctrl(
command,
port,
trans_factory=None,
prot_factory=None):
"""
service_ctrl is a generic function to execute standard fb303 functions
@param command: one of stop, start, reload, status, counters, name, alive
@param port: service's port
@param trans_factory: TTransportFactory to use for obtaining a TTransport. Default is
TBufferedTransportFactory
@param prot_factory: TProtocolFactory to use for obtaining a TProtocol. Default is
TBinaryProtocolFactory
"""
if command in ["status"]:
try:
status = fb303_wrapper('status', port, trans_factory, prot_factory)
status_details = fb303_wrapper('get_status_details', port, trans_factory, prot_factory)
msg = fb_status_string(status)
if (len(status_details)):
msg += " - %s" % status_details
print msg
if (status == fb_status.ALIVE):
return 2
else:
return 3
except:
print "Failed to get status"
return 3
# scalar commands
if command in ["version", "alive", "name"]:
try:
result = fb303_wrapper(command, port, trans_factory, prot_factory)
print result
return 0
except:
print "failed to get ", command
return 3
# counters
if command in ["counters"]:
try:
counters = fb303_wrapper('counters', port, trans_factory, prot_factory)
for counter in counters:
print "%s: %d" % (counter, counters[counter])
return 0
except:
print "failed to get counters"
return 3
# Only root should be able to run the following commands
if os.getuid() == 0:
# async commands
if command in ["stop", "reload"]:
try:
fb303_wrapper(command, port, trans_factory, prot_factory)
return 0
except:
print "failed to tell the service to ", command
return 3
else:
if command in ["stop", "reload"]:
print "root privileges are required to stop or reload the service."
return 4
print "The following commands are available:"
for command in ["counters", "name", "version", "alive", "status"]:
print "\t%s" % command
print "The following commands are available for users with root privileges:"
for command in ["stop", "reload"]:
print "\t%s" % command
return 0
def fb303_wrapper(command, port, trans_factory=None, prot_factory=None):
sock = TSocket.TSocket('localhost', port)
# use input transport factory if provided
if (trans_factory is None):
trans = TTransport.TBufferedTransport(sock)
else:
trans = trans_factory.getTransport(sock)
# use input protocol factory if provided
if (prot_factory is None):
prot = TBinaryProtocol.TBinaryProtocol(trans)
else:
prot = prot_factory.getProtocol(trans)
# initialize client and open transport
fb303_client = FacebookService.Client(prot, prot)
trans.open()
if (command == 'reload'):
fb303_client.reinitialize()
elif (command == 'stop'):
fb303_client.shutdown()
elif (command == 'status'):
return fb303_client.getStatus()
elif (command == 'version'):
return fb303_client.getVersion()
elif (command == 'get_status_details'):
return fb303_client.getStatusDetails()
elif (command == 'counters'):
return fb303_client.getCounters()
elif (command == 'name'):
return fb303_client.getName()
elif (command == 'alive'):
return fb303_client.aliveSince()
trans.close()
def fb_status_string(status_enum):
if (status_enum == fb_status.DEAD):
return "DEAD"
if (status_enum == fb_status.STARTING):
return "STARTING"
if (status_enum == fb_status.ALIVE):
return "ALIVE"
if (status_enum == fb_status.STOPPING):
return "STOPPING"
if (status_enum == fb_status.STOPPED):
return "STOPPED"
if (status_enum == fb_status.WARNING):
return "WARNING"
def main():
# parse command line options
parser = OptionParser()
commands = ["stop", "counters", "status", "reload", "version", "name", "alive"]
parser.add_option("-c", "--command", dest="command", help="execute this API",
choices=commands, default="status")
parser.add_option("-p", "--port", dest="port", help="the service's port",
default=9082)
(options, args) = parser.parse_args()
status = service_ctrl(options.command, options.port)
sys.exit(status)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,48 @@
#!/usr/bin/env python
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
import sys
try:
from setuptools import setup, Extension
except:
from distutils.core import setup, Extension, Command
setup(name='thrift_fb303',
version='0.10.0',
description='Python bindings for the Apache Thrift FB303',
author=['Thrift Developers'],
author_email=['dev@thrift.apache.org'],
url='http://thrift.apache.org',
license='Apache License 2.0',
packages=[
'fb303',
'fb303_scripts',
],
classifiers=[
'Development Status :: 5 - Production/Stable',
'Environment :: Console',
'Intended Audience :: Developers',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Topic :: Software Development :: Libraries',
'Topic :: System :: Networking'
],
)

View file

@ -0,0 +1,19 @@
#!/bin/sh
set -e
./configure \
--disable-libs \
--build=i686-pc-linux-gnu \
--host=i586-mingw32msvc \
CC=i586-mingw32msvc-gcc CXX=i586-mingw32msvc-g++
make
# Check two locations to be compatible with libtool 1.5.26 or 2.2.6b.
if test -f compiler/cpp/.libs/thrift.exe ; then
i586-mingw32msvc-strip compiler/cpp/.libs/thrift.exe -o ./thrift.exe
else
i586-mingw32msvc-strip compiler/cpp/thrift.exe -o ./thrift.exe
fi
echo "Finished compiling with resulting exe"
ls -l ./thrift.exe

312
vendor/git.apache.org/thrift.git/contrib/parse_profiling.py generated vendored Executable file
View file

@ -0,0 +1,312 @@
#!/usr/bin/env python
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
"""
This script can be used to make the output from
apache::thrift::profile_print_info() more human-readable.
It translates each executable file name and address into the corresponding
source file name, line number, and function name. By default, it also
demangles C++ symbol names.
"""
import optparse
import os
import re
import subprocess
import sys
class AddressInfo(object):
"""
A class to store information about a particular address in an object file.
"""
def __init__(self, obj_file, address):
self.objectFile = obj_file
self.address = address
self.sourceFile = None
self.sourceLine = None
self.function = None
g_addrs_by_filename = {}
def get_address(filename, address):
"""
Retrieve an AddressInfo object for the specified object file and address.
Keeps a global list of AddressInfo objects. Two calls to get_address()
with the same filename and address will always return the same AddressInfo
object.
"""
global g_addrs_by_filename
try:
by_address = g_addrs_by_filename[filename]
except KeyError:
by_address = {}
g_addrs_by_filename[filename] = by_address
try:
addr_info = by_address[address]
except KeyError:
addr_info = AddressInfo(filename, address)
by_address[address] = addr_info
return addr_info
def translate_file_addresses(filename, addresses, options):
"""
Use addr2line to look up information for the specified addresses.
All of the addresses must belong to the same object file.
"""
# Do nothing if we can't find the file
if not os.path.isfile(filename):
return
args = ['addr2line']
if options.printFunctions:
args.append('-f')
args.extend(['-e', filename])
proc = subprocess.Popen(args, stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
for address in addresses:
assert address.objectFile == filename
proc.stdin.write(address.address + '\n')
if options.printFunctions:
function = proc.stdout.readline()
function = function.strip()
if not function:
raise Exception('unexpected EOF from addr2line')
address.function = function
file_and_line = proc.stdout.readline()
file_and_line = file_and_line.strip()
if not file_and_line:
raise Exception('unexpected EOF from addr2line')
idx = file_and_line.rfind(':')
if idx < 0:
msg = 'expected file and line number from addr2line; got %r' % \
(file_and_line,)
msg += '\nfile=%r, address=%r' % (filename, address.address)
raise Exception(msg)
address.sourceFile = file_and_line[:idx]
address.sourceLine = file_and_line[idx + 1:]
(remaining_out, cmd_err) = proc.communicate()
retcode = proc.wait()
if retcode != 0:
raise subprocess.CalledProcessError(retcode, args)
def lookup_addresses(options):
"""
Look up source file information for all of the addresses currently stored
in the global list of AddressInfo objects.
"""
global g_addrs_by_filename
for (file, addresses) in g_addrs_by_filename.items():
translate_file_addresses(file, addresses.values(), options)
class Entry(object):
"""
An entry in the thrift profile output.
Contains a header line, and a backtrace.
"""
def __init__(self, header):
self.header = header
self.bt = []
def addFrame(self, filename, address):
# If libc was able to determine the symbols names, the filename
# argument will be of the form <filename>(<function>+<offset>)
# So, strip off anything after the last '('
idx = filename.rfind('(')
if idx >= 0:
filename = filename[:idx]
addr = get_address(filename, address)
self.bt.append(addr)
def write(self, f, options):
f.write(self.header)
f.write('\n')
n = 0
for address in self.bt:
f.write(' #%-2d %s:%s\n' % (n, address.sourceFile,
address.sourceLine))
n += 1
if options.printFunctions:
if address.function:
f.write(' %s\n' % (address.function,))
else:
f.write(' ??\n')
def process_file(in_file, out_file, options):
"""
Read thrift profile output from the specified input file, and print
prettier information on the output file.
"""
#
# A naive approach would be to read the input line by line,
# and each time we come to a filename and address, pass it to addr2line
# and print the resulting information. Unfortunately, addr2line can be
# quite slow, especially with large executables.
#
# This approach is much faster. We read in all of the input, storing
# the addresses in each file that need to be resolved. We then call
# addr2line just once for each file. This is much faster than calling
# addr2line once per address.
#
virt_call_regex = re.compile(r'^\s*T_VIRTUAL_CALL: (\d+) calls on (.*):$')
gen_prot_regex = re.compile(
r'^\s*T_GENERIC_PROTOCOL: (\d+) calls to (.*) with a (.*):$')
bt_regex = re.compile(r'^\s*#(\d+)\s*(.*) \[(0x[0-9A-Za-z]+)\]$')
# Parse all of the input, and store it as Entry objects
entries = []
current_entry = None
while True:
line = in_file.readline()
if not line:
break
if line == '\n' or line.startswith('Thrift virtual call info:'):
continue
virt_call_match = virt_call_regex.match(line)
if virt_call_match:
num_calls = int(virt_call_match.group(1))
type_name = virt_call_match.group(2)
if options.cxxfilt:
# Type names reported by typeid() are internal names.
# By default, c++filt doesn't demangle internal type names.
# (Some versions of c++filt have a "-t" option to enable this.
# Other versions don't have this argument, but demangle type
# names passed as an argument, but not on stdin.)
#
# If the output is being filtered through c++filt, prepend
# "_Z" to the type name to make it look like an external name.
type_name = '_Z' + type_name
header = 'T_VIRTUAL_CALL: %d calls on "%s"' % \
(num_calls, type_name)
if current_entry is not None:
entries.append(current_entry)
current_entry = Entry(header)
continue
gen_prot_match = gen_prot_regex.match(line)
if gen_prot_match:
num_calls = int(gen_prot_match.group(1))
type_name1 = gen_prot_match.group(2)
type_name2 = gen_prot_match.group(3)
if options.cxxfilt:
type_name1 = '_Z' + type_name1
type_name2 = '_Z' + type_name2
header = 'T_GENERIC_PROTOCOL: %d calls to "%s" with a "%s"' % \
(num_calls, type_name1, type_name2)
if current_entry is not None:
entries.append(current_entry)
current_entry = Entry(header)
continue
bt_match = bt_regex.match(line)
if bt_match:
if current_entry is None:
raise Exception('found backtrace frame before entry header')
frame_num = int(bt_match.group(1))
filename = bt_match.group(2)
address = bt_match.group(3)
current_entry.addFrame(filename, address)
continue
raise Exception('unexpected line in input: %r' % (line,))
# Add the last entry we were processing to the list
if current_entry is not None:
entries.append(current_entry)
current_entry = None
# Look up all of the addresses
lookup_addresses(options)
# Print out the entries, now that the information has been translated
for entry in entries:
entry.write(out_file, options)
out_file.write('\n')
def start_cppfilt():
(read_pipe, write_pipe) = os.pipe()
# Fork. Run c++filt in the parent process,
# and then continue normal processing in the child.
pid = os.fork()
if pid == 0:
# child
os.dup2(write_pipe, sys.stdout.fileno())
os.close(read_pipe)
os.close(write_pipe)
return
else:
# parent
os.dup2(read_pipe, sys.stdin.fileno())
os.close(read_pipe)
os.close(write_pipe)
cmd = ['c++filt']
os.execvp(cmd[0], cmd)
def main(argv):
parser = optparse.OptionParser(usage='%prog [options] [<file>]')
parser.add_option('--no-functions', help='Don\'t print function names',
dest='printFunctions', action='store_false',
default=True)
parser.add_option('--no-demangle',
help='Don\'t demangle C++ symbol names',
dest='cxxfilt', action='store_false',
default=True)
(options, args) = parser.parse_args(argv[1:])
num_args = len(args)
if num_args == 0:
in_file = sys.stdin
elif num_args == 1:
in_file = open(argv[1], 'r')
else:
parser.print_usage(sys.stderr)
print >> sys.stderr, 'trailing arguments: %s' % (' '.join(args[1:],))
return 1
if options.cxxfilt:
start_cppfilt()
process_file(in_file, sys.stdout, options)
if __name__ == '__main__':
rc = main(sys.argv)
sys.exit(rc)

View file

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.
-->
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.thrift</groupId>
<artifactId>thrift-maven-plugin</artifactId>
<packaging>maven-plugin</packaging>
<name>thrift-maven-plugin</name>
<version>0.10.0</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.14.1</version>
<configuration>
<systemPropertyVariables>
<thriftExecutable>${thrift.compiler}</thriftExecutable>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-project</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-utils</artifactId>
<version>3.0.14</version>
</dependency>
</dependencies>
<properties>
<thrift.root>${basedir}/../..</thrift.root>
<thrift.compiler>${thrift.root}/compiler/cpp/thrift</thrift.compiler>
<thrift.test.home>${thrift.root}/test</thrift.test.home>
</properties>
</project>

View file

@ -0,0 +1,377 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.thrift.maven;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableSet;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectHelper;
import org.codehaus.plexus.util.cli.CommandLineException;
import org.codehaus.plexus.util.io.RawInputStreamFacade;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Sets.newHashSet;
import static java.lang.String.format;
import static java.util.Arrays.asList;
import static java.util.Collections.list;
import static org.codehaus.plexus.util.FileUtils.cleanDirectory;
import static org.codehaus.plexus.util.FileUtils.copyStreamToFile;
import static org.codehaus.plexus.util.FileUtils.getFiles;
/**
* Abstract Mojo implementation.
* <p/>
* This class is extended by {@link org.apache.thrift.maven.ThriftCompileMojo} and
* {@link org.apache.thrift.maven.ThriftTestCompileMojo} in order to override the specific configuration for
* compiling the main or test classes respectively.
*/
abstract class AbstractThriftMojo extends AbstractMojo {
private static final String THRIFT_FILE_SUFFIX = ".thrift";
private static final String DEFAULT_INCLUDES = "**/*" + THRIFT_FILE_SUFFIX;
/**
* The current Maven project.
*
* @parameter default-value="${project}"
* @readonly
* @required
*/
protected MavenProject project;
/**
* A helper used to add resources to the project.
*
* @component
* @required
*/
protected MavenProjectHelper projectHelper;
/**
* This is the path to the {@code thrift} executable. By default it will search the {@code $PATH}.
*
* @parameter default-value="thrift"
* @required
*/
private String thriftExecutable;
/**
* This string is passed to the {@code --gen} option of the {@code thrift} parameter. By default
* it will generate Java output. The main reason for this option is to be able to add options
* to the Java generator - if you generate something else, you're on your own.
*
* @parameter default-value="java"
*/
private String generator;
/**
* @parameter
*/
private File[] additionalThriftPathElements = new File[]{};
/**
* Since {@code thrift} cannot access jars, thrift files in dependencies are extracted to this location
* and deleted on exit. This directory is always cleaned during execution.
*
* @parameter default-value="${project.build.directory}/thrift-dependencies"
* @required
*/
private File temporaryThriftFileDirectory;
/**
* This is the path to the local maven {@code repository}.
*
* @parameter default-value="${localRepository}"
* @required
*/
private ArtifactRepository localRepository;
/**
* Set this to {@code false} to disable hashing of dependent jar paths.
* <p/>
* This plugin expands jars on the classpath looking for embedded .thrift files.
* Normally these paths are hashed (MD5) to avoid issues with long file names on windows.
* However if this property is set to {@code false} longer paths will be used.
*
* @parameter default-value="true"
* @required
*/
private boolean hashDependentPaths;
/**
* @parameter
*/
private Set<String> includes = ImmutableSet.of(DEFAULT_INCLUDES);
/**
* @parameter
*/
private Set<String> excludes = ImmutableSet.of();
/**
* @parameter
*/
private long staleMillis = 0;
/**
* @parameter
*/
private boolean checkStaleness = false;
/**
* Executes the mojo.
*/
public void execute() throws MojoExecutionException, MojoFailureException {
checkParameters();
final File thriftSourceRoot = getThriftSourceRoot();
if (thriftSourceRoot.exists()) {
try {
ImmutableSet<File> thriftFiles = findThriftFilesInDirectory(thriftSourceRoot);
final File outputDirectory = getOutputDirectory();
ImmutableSet<File> outputFiles = findGeneratedFilesInDirectory(getOutputDirectory());
if (thriftFiles.isEmpty()) {
getLog().info("No thrift files to compile.");
} else if (checkStaleness && ((lastModified(thriftFiles) + staleMillis) < lastModified(outputFiles))) {
getLog().info("Skipping compilation because target directory newer than sources.");
attachFiles();
} else {
ImmutableSet<File> derivedThriftPathElements =
makeThriftPathFromJars(temporaryThriftFileDirectory, getDependencyArtifactFiles());
outputDirectory.mkdirs();
// Quick fix to fix issues with two mvn installs in a row (ie no clean)
// cleanDirectory(outputDirectory);
Thrift thrift = new Thrift.Builder(thriftExecutable, outputDirectory)
.setGenerator(generator)
.addThriftPathElement(thriftSourceRoot)
.addThriftPathElements(derivedThriftPathElements)
.addThriftPathElements(asList(additionalThriftPathElements))
.addThriftFiles(thriftFiles)
.build();
final int exitStatus = thrift.compile();
if (exitStatus != 0) {
getLog().error("thrift failed output: " + thrift.getOutput());
getLog().error("thrift failed error: " + thrift.getError());
throw new MojoFailureException(
"thrift did not exit cleanly. Review output for more information.");
}
attachFiles();
}
} catch (IOException e) {
throw new MojoExecutionException("An IO error occurred", e);
} catch (IllegalArgumentException e) {
throw new MojoFailureException("thrift failed to execute because: " + e.getMessage(), e);
} catch (CommandLineException e) {
throw new MojoExecutionException("An error occurred while invoking thrift.", e);
}
} else {
getLog().info(format("%s does not exist. Review the configuration or consider disabling the plugin.",
thriftSourceRoot));
}
}
ImmutableSet<File> findGeneratedFilesInDirectory(File directory) throws IOException {
if (directory == null || !directory.isDirectory())
return ImmutableSet.of();
List<File> javaFilesInDirectory = getFiles(directory, "**/*.java", null);
return ImmutableSet.copyOf(javaFilesInDirectory);
}
private long lastModified(ImmutableSet<File> files) {
long result = 0;
for (File file : files) {
if (file.lastModified() > result)
result = file.lastModified();
}
return result;
}
private void checkParameters() {
checkNotNull(project, "project");
checkNotNull(projectHelper, "projectHelper");
checkNotNull(thriftExecutable, "thriftExecutable");
checkNotNull(generator, "generator");
final File thriftSourceRoot = getThriftSourceRoot();
checkNotNull(thriftSourceRoot);
checkArgument(!thriftSourceRoot.isFile(), "thriftSourceRoot is a file, not a diretory");
checkNotNull(temporaryThriftFileDirectory, "temporaryThriftFileDirectory");
checkState(!temporaryThriftFileDirectory.isFile(), "temporaryThriftFileDirectory is a file, not a directory");
final File outputDirectory = getOutputDirectory();
checkNotNull(outputDirectory);
checkState(!outputDirectory.isFile(), "the outputDirectory is a file, not a directory");
}
protected abstract File getThriftSourceRoot();
protected abstract List<Artifact> getDependencyArtifacts();
protected abstract File getOutputDirectory();
protected abstract void attachFiles();
/**
* Gets the {@link File} for each dependency artifact.
*
* @return A set of all dependency artifacts.
*/
private ImmutableSet<File> getDependencyArtifactFiles() {
Set<File> dependencyArtifactFiles = newHashSet();
for (Artifact artifact : getDependencyArtifacts()) {
dependencyArtifactFiles.add(artifact.getFile());
}
return ImmutableSet.copyOf(dependencyArtifactFiles);
}
/**
* @throws IOException
*/
ImmutableSet<File> makeThriftPathFromJars(File temporaryThriftFileDirectory, Iterable<File> classpathElementFiles)
throws IOException, MojoExecutionException {
checkNotNull(classpathElementFiles, "classpathElementFiles");
// clean the temporary directory to ensure that stale files aren't used
if (temporaryThriftFileDirectory.exists()) {
cleanDirectory(temporaryThriftFileDirectory);
}
Set<File> thriftDirectories = newHashSet();
for (File classpathElementFile : classpathElementFiles) {
// for some reason under IAM, we receive poms as dependent files
// I am excluding .xml rather than including .jar as there may be other extensions in use (sar, har, zip)
if (classpathElementFile.isFile() && classpathElementFile.canRead() &&
!classpathElementFile.getName().endsWith(".xml")) {
// create the jar file. the constructor validates.
JarFile classpathJar;
try {
classpathJar = new JarFile(classpathElementFile);
} catch (IOException e) {
throw new IllegalArgumentException(format(
"%s was not a readable artifact", classpathElementFile));
}
for (JarEntry jarEntry : list(classpathJar.entries())) {
final String jarEntryName = jarEntry.getName();
if (jarEntry.getName().endsWith(THRIFT_FILE_SUFFIX)) {
final File uncompressedCopy =
new File(new File(temporaryThriftFileDirectory,
truncatePath(classpathJar.getName())), jarEntryName);
uncompressedCopy.getParentFile().mkdirs();
copyStreamToFile(new RawInputStreamFacade(classpathJar
.getInputStream(jarEntry)), uncompressedCopy);
thriftDirectories.add(uncompressedCopy.getParentFile());
}
}
} else if (classpathElementFile.isDirectory()) {
File[] thriftFiles = classpathElementFile.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith(THRIFT_FILE_SUFFIX);
}
});
if (thriftFiles.length > 0) {
thriftDirectories.add(classpathElementFile);
}
}
}
return ImmutableSet.copyOf(thriftDirectories);
}
ImmutableSet<File> findThriftFilesInDirectory(File directory) throws IOException {
checkNotNull(directory);
checkArgument(directory.isDirectory(), "%s is not a directory", directory);
List<File> thriftFilesInDirectory = getFiles(directory,
Joiner.on(",").join(includes),
Joiner.on(",").join(excludes));
return ImmutableSet.copyOf(thriftFilesInDirectory);
}
ImmutableSet<File> findThriftFilesInDirectories(Iterable<File> directories) throws IOException {
checkNotNull(directories);
Set<File> thriftFiles = newHashSet();
for (File directory : directories) {
thriftFiles.addAll(findThriftFilesInDirectory(directory));
}
return ImmutableSet.copyOf(thriftFiles);
}
/**
* Truncates the path of jar files so that they are relative to the local repository.
*
* @param jarPath the full path of a jar file.
* @return the truncated path relative to the local repository or root of the drive.
*/
String truncatePath(final String jarPath) throws MojoExecutionException {
if (hashDependentPaths) {
try {
return toHexString(MessageDigest.getInstance("MD5").digest(jarPath.getBytes()));
} catch (NoSuchAlgorithmException e) {
throw new MojoExecutionException("Failed to expand dependent jar", e);
}
}
String repository = localRepository.getBasedir().replace('\\', '/');
if (!repository.endsWith("/")) {
repository += "/";
}
String path = jarPath.replace('\\', '/');
int repositoryIndex = path.indexOf(repository);
if (repositoryIndex != -1) {
path = path.substring(repositoryIndex + repository.length());
}
// By now the path should be good, but do a final check to fix windows machines.
int colonIndex = path.indexOf(':');
if (colonIndex != -1) {
// 2 = :\ in C:\
path = path.substring(colonIndex + 2);
}
return path;
}
private static final char[] HEX_CHARS = "0123456789abcdef".toCharArray();
public static String toHexString(byte[] byteArray) {
final StringBuilder hexString = new StringBuilder(2 * byteArray.length);
for (final byte b : byteArray) {
hexString.append(HEX_CHARS[(b & 0xF0) >> 4]).append(HEX_CHARS[b & 0x0F]);
}
return hexString.toString();
}
}

View file

@ -0,0 +1,262 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.thrift.maven;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import org.codehaus.plexus.util.cli.CommandLineException;
import org.codehaus.plexus.util.cli.CommandLineUtils;
import org.codehaus.plexus.util.cli.Commandline;
import java.io.File;
import java.util.List;
import java.util.Set;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Lists.newLinkedList;
import static com.google.common.collect.Sets.newHashSet;
/**
* This class represents an invokable configuration of the {@code thrift}
* compiler. The actual executable is invoked using the plexus
* {@link Commandline}.
* <p/>
* This class currently only supports generating java source files.
*/
final class Thrift {
final static String GENERATED_JAVA = "gen-java";
private final String executable;
private final String generator;
private final ImmutableSet<File> thriftPathElements;
private final ImmutableSet<File> thriftFiles;
private final File javaOutputDirectory;
private final CommandLineUtils.StringStreamConsumer output;
private final CommandLineUtils.StringStreamConsumer error;
/**
* Constructs a new instance. This should only be used by the {@link Builder}.
*
* @param executable The path to the {@code thrift} executable.
* @param generator The value for the {@code --gen} option.
* @param thriftPath The directories in which to search for imports.
* @param thriftFiles The thrift source files to compile.
* @param javaOutputDirectory The directory into which the java source files
* will be generated.
*/
private Thrift(String executable, String generator, ImmutableSet<File> thriftPath,
ImmutableSet<File> thriftFiles, File javaOutputDirectory) {
this.executable = checkNotNull(executable, "executable");
this.generator = checkNotNull(generator, "generator");
this.thriftPathElements = checkNotNull(thriftPath, "thriftPath");
this.thriftFiles = checkNotNull(thriftFiles, "thriftFiles");
this.javaOutputDirectory = checkNotNull(javaOutputDirectory, "javaOutputDirectory");
this.error = new CommandLineUtils.StringStreamConsumer();
this.output = new CommandLineUtils.StringStreamConsumer();
}
/**
* Invokes the {@code thrift} compiler using the configuration specified at
* construction.
*
* @return The exit status of {@code thrift}.
* @throws CommandLineException
*/
public int compile() throws CommandLineException {
for (File thriftFile : thriftFiles) {
Commandline cl = new Commandline();
cl.setExecutable(executable);
cl.addArguments(buildThriftCommand(thriftFile).toArray(new String[]{}));
final int result = CommandLineUtils.executeCommandLine(cl, null, output, error);
if (result != 0) {
return result;
}
}
// result will always be 0 here.
return 0;
}
/**
* Creates the command line arguments.
* <p/>
* This method has been made visible for testing only.
*
* @param thriftFile
* @return A list consisting of the executable followed by any arguments.
*/
ImmutableList<String> buildThriftCommand(final File thriftFile) {
final List<String> command = newLinkedList();
// add the executable
for (File thriftPathElement : thriftPathElements) {
command.add("-I");
command.add(thriftPathElement.toString());
}
command.add("-out");
command.add(javaOutputDirectory.toString());
command.add("--gen");
command.add(generator);
command.add(thriftFile.toString());
return ImmutableList.copyOf(command);
}
/**
* @return the output
*/
public String getOutput() {
return output.getOutput();
}
/**
* @return the error
*/
public String getError() {
return error.getOutput();
}
/**
* This class builds {@link Thrift} instances.
*/
static final class Builder {
private final String executable;
private final File javaOutputDirectory;
private Set<File> thriftPathElements;
private Set<File> thriftFiles;
private String generator;
/**
* Constructs a new builder. The two parameters are present as they are
* required for all {@link Thrift} instances.
*
* @param executable The path to the {@code thrift} executable.
* @param javaOutputDirectory The directory into which the java source files
* will be generated.
* @throws NullPointerException If either of the arguments are {@code null}.
* @throws IllegalArgumentException If the {@code javaOutputDirectory} is
* not a directory.
*/
public Builder(String executable, File javaOutputDirectory) {
this.executable = checkNotNull(executable, "executable");
this.javaOutputDirectory = checkNotNull(javaOutputDirectory);
checkArgument(javaOutputDirectory.isDirectory());
this.thriftFiles = newHashSet();
this.thriftPathElements = newHashSet();
}
/**
* Adds a thrift file to be compiled. Thrift files must be on the thriftpath
* and this method will fail if a thrift file is added without first adding a
* parent directory to the thriftpath.
*
* @param thriftFile
* @return The builder.
* @throws IllegalStateException If a thrift file is added without first
* adding a parent directory to the thriftpath.
* @throws NullPointerException If {@code thriftFile} is {@code null}.
*/
public Builder addThriftFile(File thriftFile) {
checkNotNull(thriftFile);
checkArgument(thriftFile.isFile());
checkArgument(thriftFile.getName().endsWith(".thrift"));
checkThriftFileIsInThriftPath(thriftFile);
thriftFiles.add(thriftFile);
return this;
}
/**
* Adds the option string for the Thrift executable's {@code --gen} parameter.
*
* @param generator
* @return The builder
* @throws NullPointerException If {@code generator} is {@code null}.
*/
public Builder setGenerator(String generator) {
checkNotNull(generator);
this.generator = generator;
return this;
}
private void checkThriftFileIsInThriftPath(File thriftFile) {
assert thriftFile.isFile();
checkState(checkThriftFileIsInThriftPathHelper(thriftFile.getParentFile()));
}
private boolean checkThriftFileIsInThriftPathHelper(File directory) {
assert directory.isDirectory();
if (thriftPathElements.contains(directory)) {
return true;
} else {
final File parentDirectory = directory.getParentFile();
return (parentDirectory == null) ? false
: checkThriftFileIsInThriftPathHelper(parentDirectory);
}
}
/**
* @see #addThriftFile(File)
*/
public Builder addThriftFiles(Iterable<File> thriftFiles) {
for (File thriftFile : thriftFiles) {
addThriftFile(thriftFile);
}
return this;
}
/**
* Adds the {@code thriftPathElement} to the thriftPath.
*
* @param thriftPathElement A directory to be searched for imported thrift message
* buffer definitions.
* @return The builder.
* @throws NullPointerException If {@code thriftPathElement} is {@code null}.
* @throws IllegalArgumentException If {@code thriftPathElement} is not a
* directory.
*/
public Builder addThriftPathElement(File thriftPathElement) {
checkNotNull(thriftPathElement);
checkArgument(thriftPathElement.isDirectory());
thriftPathElements.add(thriftPathElement);
return this;
}
/**
* @see #addThriftPathElement(File)
*/
public Builder addThriftPathElements(Iterable<File> thriftPathElements) {
for (File thriftPathElement : thriftPathElements) {
addThriftPathElement(thriftPathElement);
}
return this;
}
/**
* @return A configured {@link Thrift} instance.
* @throws IllegalStateException If no thrift files have been added.
*/
public Thrift build() {
checkState(!thriftFiles.isEmpty());
return new Thrift(executable, generator, ImmutableSet.copyOf(thriftPathElements),
ImmutableSet.copyOf(thriftFiles), javaOutputDirectory);
}
}
}

View file

@ -0,0 +1,78 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.thrift.maven;
import java.io.File;
import java.util.List;
import org.apache.maven.artifact.Artifact;
import com.google.common.collect.ImmutableList;
/**
* This mojo executes the {@code thrift} compiler for generating java sources
* from thrift definitions. It also searches dependency artifacts for
* thrift files and includes them in the thriftPath so that they can be
* referenced. Finally, it adds the thrift files to the project as resources so
* that they are included in the final artifact.
*
* @phase generate-sources
* @goal compile
* @requiresDependencyResolution compile
*/
public final class ThriftCompileMojo extends AbstractThriftMojo {
/**
* The source directories containing the sources to be compiled.
*
* @parameter default-value="${basedir}/src/main/thrift"
* @required
*/
private File thriftSourceRoot;
/**
* This is the directory into which the {@code .java} will be created.
*
* @parameter default-value="${project.build.directory}/generated-sources/thrift"
* @required
*/
private File outputDirectory;
@Override
protected List<Artifact> getDependencyArtifacts() {
List<Artifact> compileArtifacts = project.getCompileArtifacts();
return compileArtifacts;
}
@Override
protected File getOutputDirectory() {
return outputDirectory;
}
@Override
protected File getThriftSourceRoot() {
return thriftSourceRoot;
}
@Override
protected void attachFiles() {
project.addCompileSourceRoot(outputDirectory.getAbsolutePath());
projectHelper.addResource(project, thriftSourceRoot.getAbsolutePath(),
ImmutableList.of("**/*.thrift"), null);
}
}

View file

@ -0,0 +1,74 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.thrift.maven;
import java.io.File;
import java.util.List;
import org.apache.maven.artifact.Artifact;
import com.google.common.collect.ImmutableList;
/**
* @phase generate-test-sources
* @goal testCompile
* @requiresDependencyResolution test
*/
public final class ThriftTestCompileMojo extends AbstractThriftMojo {
/**
* The source directories containing the sources to be compiled.
*
* @parameter default-value="${basedir}/src/test/thrift"
* @required
*/
private File thriftTestSourceRoot;
/**
* This is the directory into which the {@code .java} will be created.
*
* @parameter default-value="${project.build.directory}/generated-test-sources/thrift"
* @required
*/
private File outputDirectory;
@Override
protected void attachFiles() {
project.addTestCompileSourceRoot(outputDirectory.getAbsolutePath());
projectHelper.addTestResource(project, thriftTestSourceRoot.getAbsolutePath(),
ImmutableList.of("**/*.thrift"), null);
}
@Override
protected List<Artifact> getDependencyArtifacts() {
// TODO(gak): maven-project needs generics
@SuppressWarnings("unchecked")
List<Artifact> testArtifacts = project.getTestArtifacts();
return testArtifacts;
}
@Override
protected File getOutputDirectory() {
return outputDirectory;
}
@Override
protected File getThriftSourceRoot() {
return thriftTestSourceRoot;
}
}

View file

@ -0,0 +1,163 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.thrift.maven;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.cli.CommandLineException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.File;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class TestThrift {
private File testRootDir;
private File idlDir;
private File genJavaDir;
private Thrift.Builder builder;
@Before
public void setup() throws Exception {
final File tmpDir = new File(System.getProperty("java.io.tmpdir"));
testRootDir = new File(tmpDir, "thrift-test");
if (testRootDir.exists()) {
FileUtils.cleanDirectory(testRootDir);
} else {
assertTrue("Failed to create output directory for test: " + testRootDir.getPath(), testRootDir.mkdir());
}
File testResourceDir = new File("src/test/resources");
assertTrue("Unable to find test resources", testRootDir.exists());
String thriftExecutable = System.getProperty("thriftExecutable", "thrift");
if (!(new File(thriftExecutable).exists())) {
thriftExecutable = "thrift";
}
System.out.println("Thrift compiler: " + thriftExecutable);
idlDir = new File(testResourceDir, "idl");
genJavaDir = new File(testRootDir, Thrift.GENERATED_JAVA);
builder = new Thrift.Builder(thriftExecutable, testRootDir);
builder
.setGenerator("java")
.addThriftPathElement(idlDir);
}
@Test
public void testThriftCompile() throws Exception {
executeThriftCompile();
}
@Test
public void testThriftCompileWithGeneratorOption() throws Exception {
builder.setGenerator("java:private-members");
executeThriftCompile();
}
private void executeThriftCompile() throws CommandLineException {
final File thriftFile = new File(idlDir, "shared.thrift");
builder.addThriftFile(thriftFile);
final Thrift thrift = builder.build();
assertTrue("File not found: shared.thrift", thriftFile.exists());
assertFalse("gen-java directory should not exist", genJavaDir.exists());
// execute the compile
final int result = thrift.compile();
assertEquals(0, result);
assertFalse("gen-java directory was not removed", genJavaDir.exists());
assertTrue("generated java code doesn't exist",
new File(testRootDir, "shared/SharedService.java").exists());
}
@Test
public void testThriftMultipleFileCompile() throws Exception {
final File sharedThrift = new File(idlDir, "shared.thrift");
final File tutorialThrift = new File(idlDir, "tutorial.thrift");
builder.addThriftFile(sharedThrift);
builder.addThriftFile(tutorialThrift);
final Thrift thrift = builder.build();
assertTrue("File not found: shared.thrift", sharedThrift.exists());
assertFalse("gen-java directory should not exist", genJavaDir.exists());
// execute the compile
final int result = thrift.compile();
assertEquals(0, result);
assertFalse("gen-java directory was not removed", genJavaDir.exists());
assertTrue("generated java code doesn't exist",
new File(testRootDir, "shared/SharedService.java").exists());
assertTrue("generated java code doesn't exist",
new File(testRootDir, "tutorial/InvalidOperation.java").exists());
}
@Test
public void testBadCompile() throws Exception {
final File thriftFile = new File(testRootDir, "missing.thrift");
builder.addThriftPathElement(testRootDir);
// Hacking around checks in addThrift file.
assertTrue(thriftFile.createNewFile());
builder.addThriftFile(thriftFile);
assertTrue(thriftFile.delete());
final Thrift thrift = builder.build();
assertTrue(!thriftFile.exists());
assertFalse("gen-java directory should not exist", genJavaDir.exists());
// execute the compile
final int result = thrift.compile();
assertEquals(1, result);
}
@Test
public void testFileInPathPreCondition() throws Exception {
final File thriftFile = new File(testRootDir, "missing.thrift");
// Hacking around checks in addThrift file.
assertTrue(thriftFile.createNewFile());
try {
builder.addThriftFile(thriftFile);
fail("Expected IllegalStateException");
} catch (IllegalStateException e) {
}
}
@After
public void cleanup() throws Exception {
if (testRootDir.exists()) {
FileUtils.cleanDirectory(testRootDir);
assertTrue("Failed to delete output directory for test: " + testRootDir.getPath(), testRootDir.delete());
}
}
}

View file

@ -0,0 +1,36 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
/**
* This Thrift file can be included by other Thrift files that want to share
* these definitions.
*/
namespace cpp shared
namespace java shared
namespace perl shared
struct SharedStruct {
1: i32 key
2: string value
}
service SharedService {
SharedStruct getStruct(1: i32 key)
}

View file

@ -0,0 +1,152 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
# Thrift Tutorial
# Mark Slee (mcslee@facebook.com)
#
# This file aims to teach you how to use Thrift, in a .thrift file. Neato. The
# first thing to notice is that .thrift files support standard shell comments.
# This lets you make your thrift file executable and include your Thrift build
# step on the top line. And you can place comments like this anywhere you like.
#
# Before running this file, you will need to have installed the thrift compiler
# into /usr/local/bin.
/**
* The first thing to know about are types. The available types in Thrift are:
*
* bool Boolean, one byte
* byte Signed byte
* i16 Signed 16-bit integer
* i32 Signed 32-bit integer
* i64 Signed 64-bit integer
* double 64-bit floating point value
* string String
* binary Blob (byte array)
* map<t1,t2> Map from one type to another
* list<t1> Ordered list of one type
* set<t1> Set of unique elements of one type
*
* Did you also notice that Thrift supports C style comments?
*/
// Just in case you were wondering... yes. We support simple C comments too.
/**
* Thrift files can reference other Thrift files to include common struct
* and service definitions. These are found using the current path, or by
* searching relative to any paths specified with the -I compiler flag.
*
* Included objects are accessed using the name of the .thrift file as a
* prefix. i.e. shared.SharedObject
*/
include "shared.thrift"
/**
* Thrift files can namespace, package, or prefix their output in various
* target languages.
*/
namespace cpp tutorial
namespace java tutorial
namespace php tutorial
namespace perl tutorial
namespace smalltalk.category Thrift.Tutorial
/**
* Thrift lets you do typedefs to get pretty names for your types. Standard
* C style here.
*/
typedef i32 MyInteger
/**
* Thrift also lets you define constants for use across languages. Complex
* types and structs are specified using JSON notation.
*/
const i32 INT32CONSTANT = 9853
const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'}
/**
* You can define enums, which are just 32 bit integers. Values are optional
* and start at 1 if not supplied, C style again.
*/
enum Operation {
ADD = 1,
SUBTRACT = 2,
MULTIPLY = 3,
DIVIDE = 4
}
/**
* Structs are the basic complex data structures. They are comprised of fields
* which each have an integer identifier, a type, a symbolic name, and an
* optional default value.
*
* Fields can be declared "optional", which ensures they will not be included
* in the serialized output if they aren't set. Note that this requires some
* manual management in some languages.
*/
struct Work {
1: i32 num1 = 0,
2: i32 num2,
3: Operation op,
4: optional string comment,
}
/**
* Structs can also be exceptions, if they are nasty.
*/
exception InvalidOperation {
1: i32 what,
2: string why
}
/**
* Ahh, now onto the cool part, defining a service. Services just need a name
* and can optionally inherit from another service using the extends keyword.
*/
service Calculator extends shared.SharedService {
/**
* A method definition looks like C code. It has a return type, arguments,
* and optionally a list of exceptions that it may throw. Note that argument
* lists and exception lists are specified using the exact same syntax as
* field lists in struct or exception definitions.
*/
void ping(),
i32 add(1:i32 num1, 2:i32 num2),
i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch),
/**
* This method has a oneway modifier. That means the client only makes
* a request and does not listen for any response at all. Oneway methods
* must be void.
*/
oneway void zip()
}
/**
* That just about covers the basics. Take a look in the test/ folder for more
* detailed examples. After you run this file, your generated code shows up
* in folders with names gen-<language>. The generated code isn't too scary
* to look at. It even has pretty indentation.
*/

140
vendor/git.apache.org/thrift.git/contrib/thrift.el generated vendored Normal file
View file

@ -0,0 +1,140 @@
;;; thrift.el --- Major mode for Apache Thrift files
;; Keywords: files
;; Licensed to the Apache Software Foundation (ASF) under one
;; or more contributor license agreements. See the NOTICE file
;; distributed with this work for additional information
;; regarding copyright ownership. The ASF licenses this file
;; to you 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.
;;
;;; Commentary:
;;
;;; Code:
(require 'font-lock)
(defvar thrift-mode-hook nil)
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.thrift\\'" . thrift-mode))
(defvar thrift-indent-level 2
"Defines 2 spaces for thrift indentation.")
;; syntax coloring
(defconst thrift-font-lock-keywords
(list
'("\\<\\(include\\|struct\\|exception\\|typedef\\|const\\|enum\\|service\\|extends\\|void\\|oneway\\|throws\\|optional\\|required\\)\\>" . font-lock-keyword-face) ;; keywords
'("\\<\\(bool\\|byte\\|i16\\|i32\\|i64\\|double\\|string\\|binary\\|map\\|list\\|set\\)\\>" . font-lock-type-face) ;; built-in types
'("\\<\\([0-9]+\\)\\>" . font-lock-variable-name-face) ;; ordinals
'("\\<\\(\\w+\\)\\s-*(" (1 font-lock-function-name-face)) ;; functions
)
"Thrift Keywords.")
;; indentation
(defun thrift-indent-line ()
"Indent current line as Thrift code."
(interactive)
(beginning-of-line)
(if (bobp)
(indent-line-to 0)
(let ((not-indented t) cur-indent)
(if (looking-at "^[ \t]*\\(}\\|throws\\)")
(if (looking-at "^[ \t]*}")
(progn
(save-excursion
(forward-line -1)
(setq cur-indent (- (current-indentation) thrift-indent-level)))
(if (< cur-indent 0)
(setq cur-indent 0)))
(progn
(save-excursion
(forward-line -1)
(if (looking-at "^[ \t]*[\\.<>[:word:]]+[ \t]+[\\.<>[:word:]]+[ \t]*(")
(setq cur-indent (+ (current-indentation) thrift-indent-level))
(setq cur-indent (current-indentation))))))
(save-excursion
(while not-indented
(forward-line -1)
(if (looking-at "^[ \t]*}")
(progn
(setq cur-indent (current-indentation))
(setq not-indented nil))
(if (looking-at "^.*{[^}]*$")
(progn
(setq cur-indent (+ (current-indentation) thrift-indent-level))
(setq not-indented nil))
(if (bobp)
(setq not-indented nil)))
(if (looking-at "^[ \t]*throws")
(progn
(setq cur-indent (- (current-indentation) thrift-indent-level))
(if (< cur-indent 0)
(setq cur-indent 0))
(setq not-indented nil))
(if (bobp)
(setq not-indented nil)))
(if (looking-at "^[ \t]*[\\.<>[:word:]]+[ \t]+[\\.<>[:word:]]+[ \t]*([^)]*$")
(progn
(setq cur-indent (+ (current-indentation) thrift-indent-level))
(setq not-indented nil))
(if (bobp)
(setq not-indented nil)))
(if (looking-at "^[ \t]*\\/\\*")
(progn
(setq cur-indent (+ (current-indentation) 1))
(setq not-indented nil))
(if (bobp)
(setq not-indented nil)))
(if (looking-at "^[ \t]*\\*\\/")
(progn
(setq cur-indent (- (current-indentation) 1))
(setq not-indented nil))
(if (bobp)
(setq not-indented nil)))
))))
(if cur-indent
(indent-line-to cur-indent)
(indent-line-to 0)))))
;; C/C++- and sh-style comments; also allowing underscore in words
(defvar thrift-mode-syntax-table
(let ((thrift-mode-syntax-table (make-syntax-table)))
(modify-syntax-entry ?_ "w" thrift-mode-syntax-table)
(modify-syntax-entry ?# "<" thrift-mode-syntax-table) ; sh-style comments
(modify-syntax-entry ?/ ". 124" thrift-mode-syntax-table) ; c/c++-style comments
(modify-syntax-entry ?* ". 23b" thrift-mode-syntax-table)
(modify-syntax-entry ?\n ">" thrift-mode-syntax-table)
thrift-mode-syntax-table)
"Syntax table for thrift-mode")
;;;###autoload
(defun thrift-mode ()
"Mode for editing Thrift files."
(interactive)
(kill-all-local-variables)
(set-syntax-table thrift-mode-syntax-table)
(set (make-local-variable 'font-lock-defaults) '(thrift-font-lock-keywords))
(setq major-mode 'thrift-mode)
(setq mode-name "Thrift")
(run-hooks 'thrift-mode-hook)
(set (make-local-variable 'indent-line-function) 'thrift-indent-line)
)
(provide 'thrift)
;;; thrift.el ends here

238
vendor/git.apache.org/thrift.git/contrib/thrift.spec generated vendored Normal file
View file

@ -0,0 +1,238 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
%define without_java 1
%define without_python 1
%define without_tests 1
%{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
%{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")}
Name: thrift
License: Apache License v2.0
Group: Development
Summary: RPC and serialization framework
Version: 0.10.0
Release: 0
URL: http://thrift.apache.org
Packager: Thrift Developers <dev@thrift.apache.org>
Source0: %{name}-%{version}.tar.gz
BuildRequires: gcc >= 3.4.6
BuildRequires: gcc-c++
%if 0%{!?without_java:1}
BuildRequires: java-devel >= 0:1.5.0
BuildRequires: ant >= 0:1.6.5
%endif
%if 0%{!?without_python:1}
BuildRequires: python-devel
%endif
%if 0%{!?without_ruby:1}
%define gem_name %{name}
BuildRequires: ruby-devel
BuildRequires: rubygems-devel
%endif
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
%description
Thrift is a software framework for scalable cross-language services
development. It combines a powerful software stack with a code generation
engine to build services that work efficiently and seamlessly between C++,
Java, C#, Python, Ruby, Perl, PHP, Objective C/Cocoa, Smalltalk, Erlang,
Objective Caml, and Haskell.
%files
%defattr(-,root,root)
%{_bindir}/thrift
%package lib-cpp
Summary: Thrift C++ library
Group: Libraries
%description lib-cpp
C++ libraries for Thrift.
%files lib-cpp
%defattr(-,root,root)
%{_libdir}/libthrift*.so.*
%{_libdir}/libthrift*.so
%package lib-cpp-devel
Summary: Thrift C++ library development files
Group: Libraries
Requires: %{name} = %{version}-%{release}
Requires: boost-devel
%if 0%{!?without_libevent:1}
Requires: libevent-devel >= 1.2
%endif
%if 0%{!?without_zlib:1}
Requires: zlib-devel
%endif
%description lib-cpp-devel
C++ static libraries and headers for Thrift.
%files lib-cpp-devel
%defattr(-,root,root)
%{_includedir}/thrift/
%{_libdir}/libthrift*.*a
%{_libdir}/pkgconfig/thrift*.pc
%if 0%{!?without_java:1}
%package lib-java
Summary: Thrift Java library
Group: Libraries
Requires: java >= 0:1.5.0
%description lib-java
Java libraries for Thrift.
%files lib-java
%defattr(-,root,root)
%{_javadir}/*
%endif
%if 0%{!?without_python:1}
%package lib-python
Summary: Thrift Python library
Group: Libraries
%description lib-python
Python libraries for Thrift.
%files lib-python
%defattr(-,root,root)
%{python_sitearch}/*
%endif
%if 0%{!?without_ruby:1}
%package -n rubygem-%{gem_name}
Summary: Thrift Ruby library
Group: Libraries
Obsoletes: %{name}-lib-ruby
%description -n rubygem-%{gem_name}
Ruby libraries for Thrift.
%files -n rubygem-%{gem_name}
%defattr(-,root,root)
%{gem_dir}/*
%endif
%if 0%{!?without_php:1}
%package lib-php
Summary: Thrift PHP library
Group: Libraries
%description lib-php
PHP libraries for Thrift.
%files lib-php
%defattr(-,root,root)
/usr/lib/php/*
%endif
%prep
%setup -q
%build
[[ -e Makefile.in ]] || ./bootstrap.sh
export GEM_HOME=${PWD}/.gem-home
export RUBYLIB=${PWD}/lib/rb/lib
%configure \
%{?without_libevent: --without-libevent } \
%{?without_zlib: --without-zlib } \
%{?without_tests: --without-tests } \
%{?without_java: --without-java } \
%{?without_python: --without-python } \
%{?without_ruby: --without-ruby } \
%{?without_php: --without-php } \
%{!?without_php: PHP_PREFIX=${RPM_BUILD_ROOT}/usr/lib/php } \
--without-csharp \
--without-erlang \
make %{?_smp_mflags}
%if 0%{!?without_java:1}
cd lib/java
%ant
cd ../..
%endif
%if 0%{!?without_python:1}
cd lib/py
CFLAGS="%{optflags}" %{__python} setup.py build
cd ../..
%endif
%if 0%{!?without_ruby:1}
%gem_install -n lib/rb/thrift*.gem
%endif
%install
export GEM_HOME=${PWD}/.gem-home
export RUBYLIB=${PWD}/lib/rb/lib
%makeinstall
ln -s libthrift-%{version}.so ${RPM_BUILD_ROOT}%{_libdir}/libthrift.so.0
ln -s libthriftnb-%{version}.so ${RPM_BUILD_ROOT}%{_libdir}/libthriftnb.so.0
ln -s libthriftz-%{version}.so ${RPM_BUILD_ROOT}%{_libdir}/libthriftz.so.0
%if 0%{!?without_java:1}
mkdir -p $RPM_BUILD_ROOT%{_javadir}
cp -p lib/java/build/*.jar $RPM_BUILD_ROOT%{_javadir}
%endif
%if 0%{!?without_python:1}
cd lib/py
%{__python} setup.py install -O1 --skip-build --root $RPM_BUILD_ROOT
cd ../..
%endif
%if 0%{!?without_ruby:1}
mkdir -p %{buildroot}%{gem_dir}
cp -a ./%{gem_dir}/* %{buildroot}%{gem_dir}/
%endif
%clean
rm -rf ${RPM_BUILD_ROOT}
%post
umask 007
/sbin/ldconfig > /dev/null 2>&1
%postun
umask 007
/sbin/ldconfig > /dev/null 2>&1
%changelog
* Wed Oct 10 2012 Thrift Dev <dev@thrift.apache.org>
- Thrift 0.9.0 release.

91
vendor/git.apache.org/thrift.git/contrib/thrift.vim generated vendored Normal file
View file

@ -0,0 +1,91 @@
" Vim syntax file
" Language: Thrift
" Maintainer: Martin Smith <martin@facebook.com>
" Last Change: $Date: $
" Copy to ~/.vim/
" Add to ~/.vimrc
" au BufRead,BufNewFile *.thrift set filetype=thrift
" au! Syntax thrift source ~/.vim/thrift.vim
"
" $Id: $
"
" Licensed to the Apache Software Foundation (ASF) under one
" or more contributor license agreements. See the NOTICE file
" distributed with this work for additional information
" regarding copyright ownership. The ASF licenses this file
" to you 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.
"
if version < 600
syntax clear
elseif exists("b:current_syntax")
finish
endif
" Todo
syn keyword thriftTodo TODO todo FIXME fixme XXX xxx contained
" Comments
syn match thriftComment "#.*" contains=thriftTodo
syn region thriftComment start="/\*" end="\*/" contains=thriftTodo
syn match thriftComment "//.\{-}\(?>\|$\)\@="
" String
syn region thriftStringDouble matchgroup=None start=+"+ end=+"+
" Number
syn match thriftNumber "-\=\<\d\+\>" contained
" Keywords
syn keyword thriftKeyword namespace
syn keyword thriftKeyword xsd_all xsd_optional xsd_nillable xsd_attrs
syn keyword thriftKeyword include cpp_include cpp_type const optional required
syn keyword thriftBasicTypes void bool byte i8 i16 i32 i64 double string binary
syn keyword thriftStructure map list set struct typedef exception enum throws union
" Special
syn match thriftSpecial "\d\+:"
" Structure
syn keyword thriftStructure service oneway extends
"async" { return tok_async; }
"exception" { return tok_xception; }
"extends" { return tok_extends; }
"throws" { return tok_throws; }
"service" { return tok_service; }
"enum" { return tok_enum; }
"const" { return tok_const; }
if version >= 508 || !exists("did_thrift_syn_inits")
if version < 508
let did_thrift_syn_inits = 1
command! -nargs=+ HiLink hi link <args>
else
command! -nargs=+ HiLink hi def link <args>
endif
HiLink thriftComment Comment
HiLink thriftKeyword Special
HiLink thriftBasicTypes Type
HiLink thriftStructure StorageClass
HiLink thriftTodo Todo
HiLink thriftString String
HiLink thriftNumber Number
HiLink thriftSpecial Special
HiLink thriftStructure Structure
delcommand HiLink
endif
let b:current_syntax = "thrift"

View file

@ -0,0 +1,91 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include <cstdlib>
#include <iostream>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/transport/TFDTransport.h>
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/protocol/TDebugProtocol.h>
#include <thrift/protocol/TProtocolTap.h>
using namespace std;
using boost::shared_ptr;
using namespace apache::thrift::transport;
using namespace apache::thrift::protocol;
void usage() {
fprintf(stderr,
"usage: thrift_dump {-b|-f|-s} < input > ouput\n"
" -b TBufferedTransport messages\n"
" -f TFramedTransport messages\n"
" -s Raw structures\n");
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[]) {
if (argc != 2) {
usage();
}
shared_ptr<TTransport> stdin_trans(new TFDTransport(STDIN_FILENO));
shared_ptr<TTransport> itrans;
if (argv[1] == std::string("-b") || argv[1] == std::string("-s")) {
itrans.reset(new TBufferedTransport(stdin_trans));
} else if (argv[1] == std::string("-f")) {
itrans.reset(new TFramedTransport(stdin_trans));
} else {
usage();
}
shared_ptr<TProtocol> iprot(new TBinaryProtocol(itrans));
shared_ptr<TProtocol> oprot(
new TDebugProtocol(
shared_ptr<TTransport>(new TBufferedTransport(
shared_ptr<TTransport>(new TFDTransport(STDOUT_FILENO))))));
TProtocolTap tap(iprot, oprot);
try {
if (argv[1] == std::string("-s")) {
for (;;) {
tap.skip(T_STRUCT);
}
} else {
std::string name;
TMessageType messageType;
int32_t seqid;
for (;;) {
tap.readMessageBegin(name, messageType, seqid);
tap.skip(T_STRUCT);
tap.readMessageEnd();
}
}
} catch (TProtocolException exn) {
cout << "Protocol Exception: " << exn.what() << endl;
} catch (...) {
oprot->getTransport()->flush();
}
cout << endl;
return 0;
}

View file

@ -0,0 +1,61 @@
Thrift transport sample project
-------------------------------
This cross-platform project has been built with Windows Visual Studio 10 and
OSX 10.7.1's g++. The client and server support socket and pipe transports
through command-line switches.
Windows supports both named & anonymous pipes; *NIX gets only named
'pipes' at this time.
Windows-only at this time:
The client & server are double-ended. Both sides run a server and client to
enable full duplex bidirectional event signaling. They are simple command
line apps. The server runs until it's aborted (Ctl-C). The client connects to
the server, informs the server of its listening pipe/port, runs some more RPCs
and exits. The server also makes RPC calls to the client to demonstrate
bidirectional operation.
Prequisites:
Boost -- tested with Boost 1.47, other versions may work.
libthrift library -- build the library under "thrift/lib/cpp/"
thrift IDL compiler -- download from http://thrift.apache.org/download/
or build from "thrift/compiler/cpp". The IDL compiler version should
match the thrift source distribution's version. For instance, thrift-0.9.0
has a different directory structure than thrift-0.8.0 and the generated
files are not compatible.
Note: Bulding the thrift IDL compiler and library are beyond the scope
of this article. Please refer to the Thrift documentation in the respective
directories and online.
Microsoft Windows with Visual Studio 10
----------------------------------------
Copy the IDL compiler 'thrift.exe' to this project folder or to a location in the path.
Run thriftme.bat to generate the interface source from the thrift files.
Open transport-sample.sln and...
Adapt the Boost paths for the client and server projects. Right-click on each project, select
Properties, then:
Configuration Properties -> C/C++ -> General -> Additional Include Directories
Configuration Properties -> Linker -> General -> Additional Include Directories
The stock path assumes that Boost is located at the same level as the thrift repo root.
Run the following in separate command prompts from the Release or Debug
build folder:
server.exe -np test
client.exe -np test
*NIX flavors
------------
Build the thrift cpp library.
Build the IDL compiler and copy it to this project folder.
Run thriftme.sh to generate the interface source from the thrift files.
Run 'make'
Run the following in separate shells:
server/server -np /tmp/test
client/client -np /tmp/test

View file

@ -0,0 +1,39 @@
/*
transport-sample thrift IDL file .
Execute thriftme.bat under Windows to generate the cpp stubs from this IDL.
*/
// See thrift/tutorial/tutorial.thrift and shared.thrift for more extensive examples.
namespace cpp Sample
namespace java Sample
namespace perl Sample
//This struct is not used in the sample. Shown here for illustrative purposes only.
//
struct SampleStruct
{
1: i32 key
2: string value
}
//A service contains the RPC(s).
//
service SampleService
{
string HelloThere(1:string HelloString),
void ServerDoSomething(),
//Client calls this to tell server which port to connect back on.
void ClientSideListenPort(1:i16 Port),
//Named pipe version
void ClientSidePipeName(1:string name),
}
//Sample RPC on the 'client' side that the master server can call.
service SampleCallback
{
void pingclient(),
}

View file

@ -0,0 +1,37 @@
// ThriftCommon.cpp : Common functions for sample Thrift client and server
//
#include "ThriftCommon.h"
namespace thriftcommon
{
//----------------------------------------------------------------------------
//Launch child process and pass R/W anonymous pipe handles on cmd line.
//This is a simple example and does not include elevation or other
//advanced features.
//
bool LaunchAnonPipeChild(std::string app, boost::shared_ptr<TServerTransport> transport)
{
#ifdef _WIN32
PROCESS_INFORMATION pi;
STARTUPINFOA si;
GetStartupInfoA(&si); //set startupinfo for the spawned process
char handles[MAX_PATH]; //Stores pipe handles converted to text
sprintf(handles, "%s %d %d", app.c_str(),
(int)boost::shared_dynamic_cast<TPipeServer>(transport)->getClientRdPipeHandle(),
(int)boost::shared_dynamic_cast<TPipeServer>(transport)->getClientWrtPipeHandle());
//spawn the child process
if (!CreateProcessA(NULL, handles, NULL,NULL,TRUE,0,NULL,NULL,&si,&pi))
{
GlobalOutput.perror("TPipeServer CreateProcess failed, GLE=", GetLastError());
return false;
}
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
#endif
return true;
}
}

View file

@ -0,0 +1,207 @@
// ThriftCommon.h : Common includes, namespaces and templates
// for sample Thrift client and server
//
// Add the following paths to the Project's properties:
//
// Configuration Properties -> C/C++ -> General-> Additional Include Directories --
// ../;../../../lib/cpp/src;../../../../boost;../../../../boost/boost/tr1;
//
// Configuration Properties -> Linker -> General -> Additional Library Directories --
// ../../../lib/cpp/$(Configuration);../../../../Boost/lib
//
// Configuration Properties -> Linker -> Input -> Additional Dependencies --
// libthrift.lib
//
// ... adjust relative paths as necessary.
//
#ifdef _WIN32 //thrift is crashing when using boost threads on Mac OSX
# define USE_BOOST_THREAD 1
# include <boost/thread.hpp>
#else
# include <sys/socket.h>
# include <netinet/in.h>
#endif
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Required Includes
//'server' side #includes
#include <thrift/concurrency/ThreadManager.h>
#include <thrift/concurrency/PlatformThreadFactory.h>
#include <thrift/server/TThreadPoolServer.h>
#include <thrift/server/TSimpleServer.h>
//'client' side #includes
#include <thrift/transport/TPipeServer.h>
#include <thrift/transport/TPipe.h>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TTransport.h>
#include <thrift/protocol/TBinaryProtocol.h>
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Required Namespaces
//'server' side namespaces
using namespace apache::thrift::server;
using namespace apache::thrift::concurrency;
//common namespaces
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
//using namespace boost; //using ns boost can introduce type conflicts
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
namespace thriftcommon
{
//----------------------------------------------------------------------------
//
//Start the thrift 'server' (both server & client side run one for bidir event signaling)
// *** This function template will block ***
//
template <class MyHandler, class MyProcessor>
void RunThriftServer (boost::shared_ptr<MyHandler> hndlr,
int NumThreads,
boost::shared_ptr<TServerTransport> transport,
boost::shared_ptr<TServer> &server)
{
#ifdef _WIN32
if (!hndlr.get())
throw std::exception("RunThriftServer() invalid handler");
if (!transport.get())
throw std::exception("RunThriftServer() invalid transport");
#else
if ( !hndlr.get() || !transport.get() )
throw std::exception();
#endif
boost::shared_ptr<MyHandler> handler(hndlr);
boost::shared_ptr<TProcessor> processor(new MyProcessor(handler));
boost::shared_ptr<TTransportFactory> tfactory(new TBufferedTransportFactory());
boost::shared_ptr<TProtocolFactory> pfactory(new TBinaryProtocolFactory());
if(NumThreads <= 1)
{ //Single-threaded server
server.reset(new TSimpleServer(processor, transport, tfactory, pfactory));
}
else
{ //Multi-threaded server
boost::shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager(NumThreads);
boost::shared_ptr<PlatformThreadFactory> threadFactory = boost::shared_ptr<PlatformThreadFactory>(new PlatformThreadFactory());
threadManager->threadFactory(threadFactory);
threadManager->start();
server.reset(new TThreadPoolServer(processor, transport, tfactory, pfactory, threadManager));
}
printf("Starting the 'server'...\n");
server->serve();
printf("done.\n");
}
// Thrift server wrapper function that accepts a pipe name.
// A handler must be passed in to this version.
template <class MyHandler, class MyProcessor>
void RunThriftServer (boost::shared_ptr<MyHandler> hndlr, int NumThreads, std::string pipename, boost::shared_ptr<TServer> &svr)
{
#ifndef _WIN32 //Mac, *nix
unlink(pipename.c_str());
#endif
boost::shared_ptr<TServerTransport> transport(new TPipeServer(pipename, 1024, NumThreads)); //Named pipe
RunThriftServer<MyHandler, MyProcessor>(hndlr, NumThreads, transport, svr);
}
// Thrift server wrapper function that accepts a pipe name.
// This version instantiates its own handler.
template <class MyHandler, class MyProcessor>
void RunThriftServer (int NumThreads, std::string pipename)
{
boost::shared_ptr<MyHandler> handler(new MyHandler());
boost::shared_ptr<TServer> server;
RunThriftServer<MyHandler, MyProcessor>(handler, NumThreads, pipename, server);
}
// Thrift server wrapper function that accepts a socket port number.
// A handler must be passed in to this version.
template <class MyHandler, class MyProcessor>
void RunThriftServer (boost::shared_ptr<MyHandler> hndlr, int NumThreads, int Port)
{
boost::shared_ptr<TServerTransport> transport(new TServerSocket(Port));
boost::shared_ptr<TServer> server;
RunThriftServer<MyHandler, MyProcessor>(hndlr, NumThreads, transport, server);
}
// Thrift server wrapper function that accepts a socket port number.
// This version instantiates its own handler.
template <class MyHandler, class MyProcessor>
void RunThriftServer (int NumThreads, int Port)
{
boost::shared_ptr<MyHandler> handler(new MyHandler());
RunThriftServer<MyHandler, MyProcessor>(handler, NumThreads, Port);
}
//
template <class MyHandler, class MyProcessor>
void RunThriftServer (boost::shared_ptr<MyHandler> hndlr, int NumThreads, boost::shared_ptr<TServerTransport> transport)
{
boost::shared_ptr<TServer> server;
RunThriftServer<MyHandler, MyProcessor>(hndlr, NumThreads, transport, server);
}
//----------------------------------------------------------------------------
//Connect to thrift 'server' - Socket version
//(both server & client side run one for bidir event signaling)
//
template <class MyClient, class MyTransport>
void ConnectToServer (boost::shared_ptr<MyClient> &client, boost::shared_ptr<MyTransport> &transport, int Port)
{
//Client side connection using sockets transport.
boost::shared_ptr<TTransport> socket(new TSocket("localhost", Port));
transport.reset(new TBufferedTransport(socket));
boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
client.reset(new MyClient(protocol));
}
//Connect to thrift 'server' - Named Pipe version
template <class MyClient, class MyTransport>
void ConnectToServer (boost::shared_ptr<MyClient> &client, boost::shared_ptr<MyTransport> &transport, std::string pipename)
{
//Client side connection using Named Pipe transport.
boost::shared_ptr<TTransport> pipe(new TPipe(pipename));
transport.reset(new TBufferedTransport(pipe));
boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
client.reset(new MyClient(protocol));
}
//Connect to thrift 'server' - Anonymous Pipe version
//Currently only supported under Windows
#ifdef _WIN32
template <class MyClient, class MyTransport>
void ConnectToServer (boost::shared_ptr<MyClient> &client, boost::shared_ptr<MyTransport> &transport, HANDLE RdPipe, HANDLE WrtPipe)
{
//Client side connection using sockets transport.
#ifdef _WIN32
boost::shared_ptr<TTransport> pipe(new TPipe((int)RdPipe, (int)WrtPipe));
transport.reset(new TBufferedTransport(pipe));
#else
boost::shared_ptr<TTransport> socket(new TSocket("localhost"));
transport.reset(new TBufferedTransport(socket));
#endif
boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
client.reset(new MyClient(protocol));
}
#endif
//----------------------------------------------------------------------------
//Launch child process and pass R/W anonymous pipe handles on cmd line.
//Currently only supported under Windows
#ifdef _WIN32
bool LaunchAnonPipeChild(std::string app, boost::shared_ptr<TServerTransport> transport);
#endif
}

View file

@ -0,0 +1,40 @@
========================================================================
CONSOLE APPLICATION : client Project Overview
========================================================================
AppWizard has created this client application for you.
This file contains a summary of what you will find in each of the files that
make up your client application.
client.vcxproj
This is the main project file for VC++ projects generated using an Application Wizard.
It contains information about the version of Visual C++ that generated the file, and
information about the platforms, configurations, and project features selected with the
Application Wizard.
client.vcxproj.filters
This is the filters file for VC++ projects generated using an Application Wizard.
It contains information about the association between the files in your project
and the filters. This association is used in the IDE to show grouping of files with
similar extensions under a specific node (for e.g. ".cpp" files are associated with the
"Source Files" filter).
client.cpp
This is the main application source file.
/////////////////////////////////////////////////////////////////////////////
Other standard files:
StdAfx.h, StdAfx.cpp
These files are used to build a precompiled header (PCH) file
named client.pch and a precompiled types file named StdAfx.obj.
/////////////////////////////////////////////////////////////////////////////
Other notes:
AppWizard uses "TODO:" comments to indicate parts of the source code you
should add to or customize.
/////////////////////////////////////////////////////////////////////////////

View file

@ -0,0 +1,195 @@
// client->cpp : Defines the entry point for the console application.
//
// sample client command line app using Thrift IPC.
// Quick n Dirty example, may not have very robust error handling
// for the sake of simplicity.
#ifdef _WIN32
# include "stdafx.h"
#else
# include "config.h"
#endif
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Include this before the generated includes
#include "ThriftCommon.h"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Tailor these to your generated files
#include "../gen-cpp/SampleService.h"
#include "../gen-cpp/SampleCallback.h"
using namespace Sample; //declared in .thrift file
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void ClientListenerThreadProc();
bool bSocket = false;
bool bAnonPipe = false;
int srvPort;
std::string pipename;
std::string pipename_client;
#ifdef _WIN32
HANDLE hConsole;
#endif
//Customized version of printf that changes the text color
//This depends on hConsole global being initialized
void hlprintf(const char* _Format, ...)
{
#ifdef _WIN32
SetConsoleTextAttribute(hConsole, 0xE);
#endif
va_list ap;
int r;
va_start (ap, _Format);
r = vprintf (_Format, ap);
va_end (ap);
#ifdef _WIN32
SetConsoleTextAttribute(hConsole, 7);
#endif
}
//-----------------------------------------------------------------------------
// Client-side RPC implementations: Called by the server to the client for
// bidirectional eventing.
//
class SampleCallbackHandler : virtual public SampleCallbackIf {
public:
SampleCallbackHandler() {
// initialization goes here
}
void pingclient()
{
hlprintf("<<<Ping received from server (server-to-client event).\n");
}
};
//-----------------------------------------------------------------------------
#ifdef _WIN32
int _tmain(int argc, _TCHAR* argv[])
#else
int main(int argc, char **argv)
#endif
{
//Process cmd line args to determine named vs anon pipes.
bool usage = false;
#ifdef _WIN32
HANDLE ReadPipe, WritePipe;
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
#endif
//Process command line params
if(argc > 1)
{
if(_tcscmp(argv[1], TEXT("-sp")) == 0)
{ //Socket Port specified
srvPort = _tstoi(argv[2]);
bSocket = true;
}
else if(_tcscmp(argv[1], TEXT("-np")) == 0)
{ //Named Pipe specified
#ifdef _WIN32
std::wstring wpipe(argv[2]);
pipename.resize(wpipe.length());
std::copy(wpipe.begin(), wpipe.end(), pipename.begin());
#else
pipename = argv[2];
#endif
pipename_client = pipename + "_client";
}
else if(argc == 3)
{ //Anonymous Pipe specified
#ifdef _WIN32
ReadPipe = (HANDLE)_tstoi(argv[1]);
WritePipe = (HANDLE)_tstoi(argv[2]);
bAnonPipe = true;
#else
printf("Anonymous pipes not (yet) supported under *NIX\n");
#endif
}
else
usage = true;
}
else
usage = true;
if(usage)
{
hlprintf("Thrift sample client usage:\n\n");
hlprintf("Socket Port to connect to: -sp <port#>\n");
hlprintf("Named Pipe to connect to: -np <pipename> (e.g. affpipe)\n");
hlprintf("Anonymous Pipe (must be launched by anon pipe creator):\n");
hlprintf(" <Read Handle> <Write Handle>\n");
return 0;
}
//Client side connection to server.
boost::shared_ptr<SampleServiceClient> client; //Client class from Thrift-generated code.
boost::shared_ptr<TTransport> transport;
if(bSocket)
{ //Socket transport
#ifdef _WIN32
TWinsockSingleton::create();
#endif
hlprintf("Using socket transport port %d\n", srvPort);
thriftcommon::ConnectToServer<SampleServiceClient, TTransport>(client, transport, srvPort);
}
else if(!bAnonPipe)
{
hlprintf("Using Named Pipe %s\n", pipename.c_str());
thriftcommon::ConnectToServer<SampleServiceClient, TTransport>(client, transport, pipename);
}
else
{
#ifdef _WIN32
hlprintf("Using Anonymous Pipe transport\n");
thriftcommon::ConnectToServer<SampleServiceClient, TTransport>(client, transport, ReadPipe, WritePipe);
#endif
}
#ifdef _WIN32
//Start a thread to receive inbound connection from server for 2-way event signaling.
boost::thread ClientListenerThread(ClientListenerThreadProc);
#endif
try {
transport->open();
//Notify server what to connect back on.
if(bSocket)
client->ClientSideListenPort(srvPort + 1); //Socket
else if(!bAnonPipe)
client->ClientSidePipeName(pipename_client); //Named Pipe
//Run some more RPCs
std::string hellostr = "Hello how are you?";
std::string returnstr;
client->HelloThere(returnstr, hellostr);
hlprintf("\n>>>Sent: %s\n", hellostr.c_str());
hlprintf("<<<Received: %s\n", returnstr.c_str());
hlprintf("\n>>>Calling ServerDoSomething() which delays for 5 seconds.\n");
client->ServerDoSomething();
hlprintf(">>>ServerDoSomething() done.\n\n");
transport->close();
} catch (TException &tx) {
hlprintf("ERROR: %s\n", tx.what());
}
return 0;
}
//Thread Routine
void ClientListenerThreadProc()
{
if(bSocket)
thriftcommon::RunThriftServer<SampleCallbackHandler, SampleCallbackProcessor>(1, srvPort + 1);
else if(!bAnonPipe)
thriftcommon::RunThriftServer<SampleCallbackHandler, SampleCallbackProcessor>(1, pipename_client);
}

View file

@ -0,0 +1,105 @@
?<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{85FBFB54-530B-498F-9F38-44BA204FAE6A}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>client</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../;../../../lib/cpp/src;../../../../boost;../../../../boost/boost/tr1;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>../../../lib/cpp/$(Configuration);../../../../Boost/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>libthrift.lib;ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../;../../../lib/cpp/src;../../../../boost;../../../../boost/boost/tr1;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>../../../lib/cpp/$(Configuration);../../../../Boost/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>libthrift.lib;ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<None Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\gen-cpp\SampleCallback.h" />
<ClInclude Include="..\gen-cpp\SampleService.h" />
<ClInclude Include="..\gen-cpp\Sample_constants.h" />
<ClInclude Include="..\gen-cpp\Sample_types.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\ThriftCommon.cpp" />
<ClCompile Include="..\gen-cpp\SampleCallback.cpp" />
<ClCompile Include="..\gen-cpp\SampleService.cpp" />
<ClCompile Include="..\gen-cpp\Sample_constants.cpp" />
<ClCompile Include="..\gen-cpp\Sample_types.cpp" />
<ClCompile Include="client.cpp" />
<ClCompile Include="stdafx.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,66 @@
?<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Source Files\gen-cpp">
<UniqueIdentifier>{1265b3dc-91de-416f-aba6-7b750de4221e}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="targetver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\gen-cpp\Sample_types.h">
<Filter>Source Files\gen-cpp</Filter>
</ClInclude>
<ClInclude Include="..\gen-cpp\SampleService.h">
<Filter>Source Files\gen-cpp</Filter>
</ClInclude>
<ClInclude Include="..\gen-cpp\Sample_constants.h">
<Filter>Source Files\gen-cpp</Filter>
</ClInclude>
<ClInclude Include="..\gen-cpp\SampleCallback.h">
<Filter>Source Files\gen-cpp</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="client.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\gen-cpp\SampleService.cpp">
<Filter>Source Files\gen-cpp</Filter>
</ClCompile>
<ClCompile Include="..\gen-cpp\Sample_constants.cpp">
<Filter>Source Files\gen-cpp</Filter>
</ClCompile>
<ClCompile Include="..\gen-cpp\Sample_types.cpp">
<Filter>Source Files\gen-cpp</Filter>
</ClCompile>
<ClCompile Include="..\gen-cpp\SampleCallback.cpp">
<Filter>Source Files\gen-cpp</Filter>
</ClCompile>
<ClCompile Include="..\ThriftCommon.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View file

@ -0,0 +1,8 @@
// stdafx.cpp : source file that includes just the standard includes
// client.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file

View file

@ -0,0 +1,15 @@
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
// TODO: reference additional headers your program requires here

View file

@ -0,0 +1,8 @@
#pragma once
// Including SDKDDKVer.h defines the highest available Windows platform.
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
#include <SDKDDKVer.h>

View file

@ -0,0 +1,24 @@
//Missing definitions for *NIX systems. This sample project
//was initially created on Windows.
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#define TEXT(str) str
inline int Sleep(int ms)
{
return sleep(ms/1000); //sleep() param is in seconds
}
inline int _tcscmp(const char* str1, const char* str2)
{
return strcmp(str1, str2);
}
inline int _tstoi(const char* str)
{
return atoi(str);
}

View file

@ -0,0 +1,40 @@
========================================================================
CONSOLE APPLICATION : server Project Overview
========================================================================
AppWizard has created this server application for you.
This file contains a summary of what you will find in each of the files that
make up your server application.
server.vcxproj
This is the main project file for VC++ projects generated using an Application Wizard.
It contains information about the version of Visual C++ that generated the file, and
information about the platforms, configurations, and project features selected with the
Application Wizard.
server.vcxproj.filters
This is the filters file for VC++ projects generated using an Application Wizard.
It contains information about the association between the files in your project
and the filters. This association is used in the IDE to show grouping of files with
similar extensions under a specific node (for e.g. ".cpp" files are associated with the
"Source Files" filter).
server.cpp
This is the main application source file.
/////////////////////////////////////////////////////////////////////////////
Other standard files:
StdAfx.h, StdAfx.cpp
These files are used to build a precompiled header (PCH) file
named server.pch and a precompiled types file named StdAfx.obj.
/////////////////////////////////////////////////////////////////////////////
Other notes:
AppWizard uses "TODO:" comments to indicate parts of the source code you
should add to or customize.
/////////////////////////////////////////////////////////////////////////////

View file

@ -0,0 +1,168 @@
// server.cpp : Defines the entry point for the console application.
//
// sample server command line app using Thrift IPC.
//
// This is a simple demonstration of full duplex RPC. That is, each
// side runs both a client and server to enable bidirectional event
// signaling.
//
#ifdef _WIN32
# include "stdafx.h"
#else
# include "config.h"
#endif
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Include this before the generated includes
#include "ThriftCommon.h"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Tailor these to your generated files
#include "../gen-cpp/SampleService.h"
#include "../gen-cpp/SampleCallback.h"
using namespace Sample; //declared in .thrift file
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int16_t ClientPort_;
std::string ClientPipeName_;
void S2CThreadProc();
//-----------------------------------------------------------------------------
// RPC implementations
//
class SampleServiceHandler : virtual public SampleServiceIf {
public:
SampleServiceHandler() {
// Your initialization goes here
}
void HelloThere(std::string& _return, const std::string& HelloString) {
// Your implementation goes here
printf("<<<HelloThere() received string: %s\n", HelloString.c_str());
_return = "Good thank you.";
}
void ServerDoSomething() {
// Your implementation goes here
printf("ServerDoSomething(): Simulating work for 5 seconds\n");
Sleep(5000);
printf("ServerDoSomething(): Done\n");
}
void ClientSideListenPort(const int16_t ClientListenPort)
{
ClientPort_ = ClientListenPort;
ClientPipeName_ = "";
#ifdef _WIN32
printf(">>>Connecting to client on port %d\n", ClientPort_);
boost::thread Connect2ClientThread(S2CThreadProc);
#endif
}
void ClientSidePipeName(const std::string& ClientPipeName)
{
ClientPipeName_ = ClientPipeName;
ClientPort_ = 0;
#ifdef _WIN32
printf(">>>Connecting to client pipe %s\n", ClientPipeName_.c_str());
boost::thread Connect2ClientThread(S2CThreadProc);
#endif
}
};
//-----------------------------------------------------------------------------
#ifdef _WIN32
int _tmain(int argc, _TCHAR* argv[])
#else
int main(int argc, char **argv)
#endif
{
int port;
std::string pipename; //e.g. "affpipe"
bool usage = false;
//Process command line params
if(argc > 1)
{
if(_tcscmp(argv[1], TEXT("-sp")) == 0)
{ //Socket Port specified
port = _tstoi(argv[2]);
#ifdef _WIN32
TWinsockSingleton::create();
#endif
// Start the thrift server which is a blocking call.
thriftcommon::RunThriftServer<SampleServiceHandler, SampleServiceProcessor>(10, port);
}
else if(_tcscmp(argv[1], TEXT("-np")) == 0)
{ //Named Pipe specified
#ifdef _WIN32
std::wstring wpipe(argv[2]);
pipename.resize(wpipe.length());
std::copy(wpipe.begin(), wpipe.end(), pipename.begin());
#else
pipename = argv[2];
#endif
printf("Using Named Pipe %s\n", pipename.c_str());
//Thrift over Named Pipe.
thriftcommon::RunThriftServer<SampleServiceHandler, SampleServiceProcessor>(10, pipename);
}
else if(_tcscmp(argv[1], TEXT("-ap")) == 0)
{ //Anonymous Pipe specified
//This is more involved because the child needs to be launched
//after the transport is created but before the blocking server
//call.
#ifdef _WIN32
boost::shared_ptr<TServerTransport> transport(new TPipeServer()); //Anonymous pipe
thriftcommon::LaunchAnonPipeChild(".\\client.exe", transport);
boost::shared_ptr<SampleServiceHandler> handler(new SampleServiceHandler());
thriftcommon::RunThriftServer<SampleServiceHandler, SampleServiceProcessor>(handler, 10, transport);
#else
printf("Anonymous pipes not (yet) supported under *NIX\n");
#endif
}
else
usage = true;
}
else
usage = true;
if(usage)
{
printf("Thrift sample server usage:\n\n");
printf("Socket Port : -sp <port#>\n");
printf("Named Pipe : -np <pipename> (e.g. affpipe)\n");
printf("Anonymous Pipe: -ap\n");
}
return 0;
}
//Thread Routine that connects to the 'client'.
void S2CThreadProc()
{
//Master server's connection to client-side's server.
boost::shared_ptr<SampleCallbackClient> clientsrv; //Client class from Thrift-generated code.
boost::shared_ptr<TTransport> transport;
if(ClientPort_ != 0)
thriftcommon::ConnectToServer<SampleCallbackClient, TTransport>(clientsrv, transport, ClientPort_);
if(!ClientPipeName_.empty())
thriftcommon::ConnectToServer<SampleCallbackClient, TTransport>(clientsrv, transport, ClientPipeName_);
try {
transport->open();
clientsrv->pingclient();
Sleep(1500);
clientsrv->pingclient();
Sleep(1500);
clientsrv->pingclient();
transport->close();
} catch (TException &tx) {
printf("ERROR: %s\n", tx.what());
}
}

View file

@ -0,0 +1,106 @@
?<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{72FCAF29-506D-4164-9FA6-F54C5C28E79D}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>server</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../;../../../lib/cpp/src;../../../../Boost/;../../../../Boost/boost/tr1;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>../../../lib/cpp/$(Configuration);../../../../Boost/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>libthrift.lib;ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../;../../../lib/cpp/src;../../../../Boost/;../../../../Boost/boost/tr1;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>../../../lib/cpp/$(Configuration);../../../../Boost/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>libthrift.lib;ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<None Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\gen-cpp\SampleCallback.h" />
<ClInclude Include="..\gen-cpp\SampleService.h" />
<ClInclude Include="..\gen-cpp\Sample_constants.h" />
<ClInclude Include="..\gen-cpp\Sample_types.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\ThriftCommon.cpp" />
<ClCompile Include="..\gen-cpp\SampleCallback.cpp" />
<ClCompile Include="..\gen-cpp\SampleService.cpp" />
<ClCompile Include="..\gen-cpp\Sample_constants.cpp" />
<ClCompile Include="..\gen-cpp\Sample_types.cpp" />
<ClCompile Include="server.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,66 @@
?<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Source Files\gen-cpp">
<UniqueIdentifier>{dab66db8-bc45-4518-aad2-7a75696226e3}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="targetver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\gen-cpp\Sample_types.h">
<Filter>Source Files\gen-cpp</Filter>
</ClInclude>
<ClInclude Include="..\gen-cpp\SampleService.h">
<Filter>Source Files\gen-cpp</Filter>
</ClInclude>
<ClInclude Include="..\gen-cpp\Sample_constants.h">
<Filter>Source Files\gen-cpp</Filter>
</ClInclude>
<ClInclude Include="..\gen-cpp\SampleCallback.h">
<Filter>Source Files\gen-cpp</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="server.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\gen-cpp\Sample_types.cpp">
<Filter>Source Files\gen-cpp</Filter>
</ClCompile>
<ClCompile Include="..\gen-cpp\SampleService.cpp">
<Filter>Source Files\gen-cpp</Filter>
</ClCompile>
<ClCompile Include="..\gen-cpp\Sample_constants.cpp">
<Filter>Source Files\gen-cpp</Filter>
</ClCompile>
<ClCompile Include="..\gen-cpp\SampleCallback.cpp">
<Filter>Source Files\gen-cpp</Filter>
</ClCompile>
<ClCompile Include="..\ThriftCommon.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View file

@ -0,0 +1,8 @@
// stdafx.cpp : source file that includes just the standard includes
// server.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file

View file

@ -0,0 +1,15 @@
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
// TODO: reference additional headers your program requires here

View file

@ -0,0 +1,8 @@
#pragma once
// Including SDKDDKVer.h defines the highest available Windows platform.
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
#include <SDKDDKVer.h>

View file

@ -0,0 +1 @@
thrift.exe --gen cpp Sample.thrift

View file

@ -0,0 +1,24 @@
#!/bin/bash
THRIFT_COMPILER=./thrift
OUTPUT_FOLDER=$PWD
if [ ! -e "${THRIFT_COMPILER}" ]
then
THRIFT_COMPILER=thrift
command -v ${THRIFT_COMPILER} >/dev/null 2>&1
if [ $? -eq 1 ]; then
echo
echo "thrift compiler not found."
echo
exit
fi
fi
${THRIFT_COMPILER} --gen cpp Sample.thrift
echo
echo "Files have been generated in gen-cpp."
exit

View file

@ -0,0 +1,26 @@
?
Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "server", "server\server.vcxproj", "{72FCAF29-506D-4164-9FA6-F54C5C28E79D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "client", "client\client.vcxproj", "{85FBFB54-530B-498F-9F38-44BA204FAE6A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{72FCAF29-506D-4164-9FA6-F54C5C28E79D}.Debug|Win32.ActiveCfg = Debug|Win32
{72FCAF29-506D-4164-9FA6-F54C5C28E79D}.Debug|Win32.Build.0 = Debug|Win32
{72FCAF29-506D-4164-9FA6-F54C5C28E79D}.Release|Win32.ActiveCfg = Release|Win32
{72FCAF29-506D-4164-9FA6-F54C5C28E79D}.Release|Win32.Build.0 = Release|Win32
{85FBFB54-530B-498F-9F38-44BA204FAE6A}.Debug|Win32.ActiveCfg = Debug|Win32
{85FBFB54-530B-498F-9F38-44BA204FAE6A}.Debug|Win32.Build.0 = Debug|Win32
{85FBFB54-530B-498F-9F38-44BA204FAE6A}.Release|Win32.ActiveCfg = Release|Win32
{85FBFB54-530B-498F-9F38-44BA204FAE6A}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,61 @@
Apache Thrift Centos 6.5 Vagrant Support
========================================
This directory is the Vagrant project directory for Apache Thrift running on Centos 6.5. The Vagrantfile in this directory configures a Vagrant provisioned VM launched under VirtualBox. To use this project you must have a recent version of VirtualBox and Vagrant installed (in that order). To run the VM, open a shell, clone Apache Thrift, change to this directory and enter the Vagrant up command.
$ git clone https://github.com/apache/thrift
$ cd thrift/contrib/vagrant/centos-6.5
$ vagrant up
This will download and launch the base box VM under VirtualBox and run the Apache Thrift provisioning script. This will take up to an hour depending on your hardware and network. Once complete you can login to the box with Vagrant ssh. The thrift source tree from your host os is mounted at /thrift.
$ vagrant ssh
[vagrant@thrift ~]$ cd /thrift
[vagrant@thrift thrift]$ compiler/cpp/thrift --version
Thrift version 1.0.0-dev
The provisioning script (inside the Vagrantfile) runs ./bootstrap.sh, ./configure, make and make check, but does not install thrift. To install thrift run "make install".
The Vagrant base box used here is a minimal Centos 6.5 VirtualBox with 2GB RAM and 2 CPUs. For more Vagrant information: https://www.vagrantup.com. A summary of the base box preparation follows:
root password: vagrant
#Create the vagrant user and give it sudo permission
adduser vagrant
passwd vagrant
visudo : vagrant ALL=(ALL) NOPASSWD: ALL
#Defaults requiretty
#Shut down the firewall and disable it
service iptables stop
chkconfig iptables off
#Setup the vagrant ssh public key to allow vagrant to ssh
mkdir /home/vagrant/.ssh
chmod 700 /home/vagrant/.ssh
cd /home/vagrant/.ssh
wget --no-check-certificate 'https://raw.github.com/mitchellh/vagrant/master/keys/vagrant.pub' -O authorized_keys
chmod 600 /home/vagrant/.ssh/authorized_keys
chown -R vagrant /home/vagrant/.ssh
#Install EPEL (Extra Packages for Enterprise Linux) but protect the base
#repositories so that EPEL does not mask base packages
yum -y install yum-plugin-protectbase
rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
#Install perl, dynamic kernel modules, dev tools and kernel headers to support
#Virtual box additions
yum -y install perl
yum -y --enablerepo epel install dkms
yum -y groupinstall "Development Tools"
yum -y install kernel-devel
#Update everything and reboot
yum update
reboot
#Install the VirtualBox Guest additions (using VirtualBox iso)
mount /dev/cdrom /mnt
/mnt/VBoxLinuxAdditions.run
umount /mnt
See the Vagrantfile for further details

View file

@ -0,0 +1,274 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
# APACHE THRIFT PROVISIONING SCRIPT
##############################################################
# This script is used to configure the base Centos 6.5
# Vagrant box for Apache Thrift compiler and lib builds.
# The base box is Centos 6.5 with no additional packages
# except those required to support VirtualBox Guest tools:
# perl, dkms, kernel-devel and the "Development Tools" group.
# The epel repo was also added along with the
# yum-plugin-protectbase package to prefer base repo packages.
# The script below provisions ALL languages. This will take
# time. You can greatly reduce the build time by commenting
# out the LIB provisioning for uneeded language libraries.
# Expect full provisioning to take 30 minutes on a fast
# machine with an excellent Internet connection (and another
# 15 minutes for the build).
#
# Machine accounts:
# - User: vagrant/vagrant
# - Admin: root/vagrant
# Vagrant public ssh key also installed
##############################################################
$build_and_test = <<SCRIPT
echo "Provisioning system to compile and test Apache Thrift."
date > /etc/vagrant.provision_begin
# Apache Thrift compiler dependencies
#####################################
#install an updated autoconf
wget http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz
tar xvf autoconf-2.69.tar.gz
cd autoconf-2.69
./configure --prefix=/usr
make
sudo make install
cd ..
#install an updated automake
wget http://ftp.gnu.org/gnu/automake/automake-1.14.tar.gz
tar xvf automake-1.14.tar.gz
cd automake-1.14
./configure --prefix=/usr
make
sudo make install
cd ..
#install an updated bison
wget http://ftp.gnu.org/gnu/bison/bison-2.5.1.tar.gz
tar xvf bison-2.5.1.tar.gz
cd bison-2.5.1
./configure --prefix=/usr
make
sudo make install
cd ..
# C++98 LIB Dependencies
#####################################
sudo yum -y install libevent-devel zlib-devel openssl-devel
#Install an updated Boost library
wget http://sourceforge.net/projects/boost/files/boost/1.55.0/boost_1_55_0.tar.gz
tar xvf boost_1_55_0.tar.gz
cd boost_1_55_0
./bootstrap.sh
sudo ./b2 install
# Java LIB Dependencies
#####################################
sudo yum install -y ant junit ant-nodeps ant-junit java-1.7.0-openjdk-devel
# Python LIB Dependencies
#####################################
sudo yum install -y python-devel python-setuptools python-twisted
# Ruby LIB Dependencies
#####################################
sudo yum install -y ruby ruby-devel rubygems
sudo gem install bundler rake
# Node.js LIB Dependencies
#####################################
sudo yum install -y nodejs nodejs-devel npm
# Perl LIB Dependencies
#####################################
sudo yum install -y perl-Bit-Vector perl-Class-Accessor perl-ExtUtils-MakeMaker perl-Test-Simple
# PHP LIB Dependencies
#####################################
sudo yum install -y php php-devel php-pear re2c
# GLibC LIB Dependencies
#####################################
sudo yum install -y glib2-devel
# Erlang LIB Dependencies
#####################################
sudo yum install -y erlang-kernel erlang-erts erlang-stdlib erlang-eunit erlang-rebar
# Lua LIB Dependencies
#####################################
sudo yum install -y lua-devel
# Go LIB Dependencies
#####################################
sudo yum install -y golang golang-pkg-linux-amd64
# C# LIB Dependencies
#####################################
sudo yum install -y mono-core mono-devel mono-web-devel mono-extras mingw32-binutils mingw32-runtime mingw32-nsis
# Haskell LIB Dependencies
#####################################
wget http://sherkin.justhub.org/el6/RPMS/x86_64/justhub-release-2.0-4.0.el6.x86_64.rpm
sudo rpm -ivh justhub-release-2.0-4.0.el6.x86_64.rpm
sudo yum -y install haskell
sudo cabal update
sudo cabal install cabal-install
# Build and Test Apache Thrift
#####################################
date > /etc/vagrant.provision_end
echo "Starting Apache Thrift build..."
cd /thrift
sh bootstrap.sh
# At the time of this file's creation Ruby, Python, Go and Lua fail
# their unit tests in this environment. To build and test any of these
# libraries uncomment the appropriate --without switches below.
sh configure --without-ruby --without-go --without-lua --without-python
make
echo "Starting Apache Thrift tests..."
make check
echo "Finished building and testing Apache Thrift."
echo 'Use "make install" to install the compiler and libraries.'
date > /etc/vagrant.make_end
SCRIPT
Vagrant.configure("2") do |config|
# Every Vagrant virtual environment requires a box to build off of.
##### Centos 6.5 minimal system with VirtualBox Guest Additions
##### Box maintained by ra@apache.org, see README.md for box config
config.vm.box = "RandyAbernethy/thrift-centos-6.5-64"
# Disable automatic box update checking. If you disable this, then
# boxes will only be checked for updates when the user runs
# `vagrant box outdated`. This is not recommended.
##### This box will never change
config.vm.box_check_update = false
# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine. In the example below,
# accessing "localhost:8080" will access port 80 on the guest machine.
# config.vm.network "forwarded_port", guest: 80, host: 8080
# Create a private network, which allows host-only access to the machine
# using a specific IP.
# config.vm.network "private_network", ip: "192.168.33.10"
# Create a public network, which generally matched to bridged network.
# Bridged networks make the machine appear as another physical device on
# your network.
# config.vm.network "public_network"
# If true, then any SSH connections made will enable agent forwarding.
# Default value: false
# config.ssh.forward_agent = true
# Share an additional folder to the guest VM. The first argument is
# the path on the host to the actual folder. The second argument is
# the path on the guest to mount the folder. And the optional third
# argument is a set of non-required options.
# config.vm.synced_folder "../data", "/vagrant_data"
##### By convention the thrift source tree is mapped to /thrift
config.vm.synced_folder "../../../", "/thrift"
# Provider-specific configuration so you can fine-tune various
# backing providers for Vagrant. These expose provider-specific options.
##### The machine needs 2 CPUs and 2GB RAM for reasonable performance
config.vm.provider "virtualbox" do |vb|
vb.customize ["modifyvm", :id, "--memory", "2048"]
vb.customize ["modifyvm", :id, "--cpus", "2"]
end
# Enable provisioning with CFEngine. CFEngine Community packages are
# automatically installed. For example, configure the host as a
# policy server and optionally a policy file to run:
#
# config.vm.provision "cfengine" do |cf|
# cf.am_policy_hub = true
# # cf.run_file = "motd.cf"
# end
#
# You can also configure and bootstrap a client to an existing
# policy server:
#
# config.vm.provision "cfengine" do |cf|
# cf.policy_server_address = "10.0.2.15"
# end
# Enable provisioning with Puppet stand alone. Puppet manifests
# are contained in a directory path relative to this Vagrantfile.
# You will need to create the manifests directory and a manifest in
# the file default.pp in the manifests_path directory.
#
# config.vm.provision "puppet" do |puppet|
# puppet.manifests_path = "manifests"
# puppet.manifest_file = "default.pp"
# end
# Enable provisioning with chef solo, specifying a cookbooks path, roles
# path, and data_bags path (all relative to this Vagrantfile), and adding
# some recipes and/or roles.
#
# config.vm.provision "chef_solo" do |chef|
# chef.cookbooks_path = "../my-recipes/cookbooks"
# chef.roles_path = "../my-recipes/roles"
# chef.data_bags_path = "../my-recipes/data_bags"
# chef.add_recipe "mysql"
# chef.add_role "web"
#
# # You may also specify custom JSON attributes:
# chef.json = { mysql_password: "foo" }
# end
# Enable provisioning with chef server, specifying the chef server URL,
# and the path to the validation key (relative to this Vagrantfile).
#
# The Opscode Platform uses HTTPS. Substitute your organization for
# ORGNAME in the URL and validation key.
#
# If you have your own Chef Server, use the appropriate URL, which may be
# HTTP instead of HTTPS depending on your configuration. Also change the
# validation key to validation.pem.
#
# config.vm.provision "chef_client" do |chef|
# chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME"
# chef.validation_key_path = "ORGNAME-validator.pem"
# end
#
# If you're using the Opscode platform, your validator client is
# ORGNAME-validator, replacing ORGNAME with your organization name.
#
# If you have your own Chef Server, the default validation client name is
# chef-validator, unless you changed the configuration.
#
# chef.validation_client_name = "ORGNAME-validator"
##### Run the Apache Thrift provisioning script (declared above)
config.vm.provision :shell, :inline => $build_and_test
end

View file

@ -0,0 +1,30 @@
This directory contains some glue code to allow Thrift RPCs to be sent over
ZeroMQ. Included are client and server implementations for Python and C++,
along with a simple demo interface (with a working client and server for
each language).
Thrift was designed for stream-based interfaces like TCP, but ZeroMQ is
message-based, so there is a small impedance mismatch. Most of issues are
hidden from developers, but one cannot be: oneway methods have to be handled
differently from normal ones. ZeroMQ requires the messaging pattern to be
declared at socket creation time, so an application cannot decide on a
message-by-message basis whether to send a reply. Therefore, this
implementation makes it the client's responsibility to ensure that ZMQ_REQ
sockets are used for normal methods and ZMQ_DOWNSTREAM sockets are used for
oneway methods. In addition, services that expose both types of methods
have to expose two servers (on two ports), but the TZmqMultiServer makes it
easy to run the two together in the same thread.
This code was tested with ZeroMQ 2.0.7 and pyzmq afabbb5b9bd3.
To build, simply install Thrift and ZeroMQ, then run "make". If you install
in a non-standard location, make sure to set THRIFT to the location of the
Thrift code generator on the make command line and PKG_CONFIG_PATH to a path
that includes the pkgconfig files for both Thrift and ZeroMQ. The test
servers take no arguments. Run the test clients with no arguments to
retrieve the stored value or with an integer argument to increment it by
that amount.
This code is not quite what I would consider production-ready. It doesn't
support all of the normal hooks into Thrift, and its performance is
sub-optimal because it does some unnecessary copying.

View file

@ -0,0 +1,48 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include "TZmqClient.h"
#include <cstring>
namespace apache { namespace thrift { namespace transport {
uint32_t TZmqClient::read_virt(uint8_t* buf, uint32_t len) {
if (rbuf_.available_read() == 0) {
(void)sock_.recv(&msg_);
rbuf_.resetBuffer((uint8_t*)msg_.data(), msg_.size());
}
return rbuf_.read(buf, len);
}
void TZmqClient::write_virt(const uint8_t* buf, uint32_t len) {
return wbuf_.write(buf, len);
}
uint32_t TZmqClient::writeEnd() {
uint8_t* buf;
uint32_t size;
wbuf_.getBuffer(&buf, &size);
zmq::message_t msg(size);
std::memcpy(msg.data(), buf, size);
(void)sock_.send(msg);
wbuf_.resetBuffer(true);
return size;
}
}}} // apache::thrift::transport

View file

@ -0,0 +1,65 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#ifndef _THRIFT_TRANSPORT_TZMQCLIENT_H_
#define _THRIFT_TRANSPORT_TZMQCLIENT_H_ 1
#include <zmq.hpp>
#include <thrift/transport/TBufferTransports.h>
namespace apache { namespace thrift { namespace transport {
class TZmqClient : public TTransport {
public:
TZmqClient(zmq::context_t& ctx, const std::string& endpoint, int type)
: sock_(ctx, type)
, endpoint_(endpoint)
, wbuf_()
, rbuf_()
, msg_()
, zmq_type_(type)
{}
void open() {
if(zmq_type_ == ZMQ_PUB) {
sock_.bind(endpoint_.c_str());
}
else {
sock_.connect(endpoint_.c_str());
}
}
uint32_t read_virt(uint8_t* buf, uint32_t len);
void write_virt(const uint8_t* buf, uint32_t len);
uint32_t writeEnd();
protected:
zmq::socket_t sock_;
std::string endpoint_;
TMemoryBuffer wbuf_;
TMemoryBuffer rbuf_;
zmq::message_t msg_;
int zmq_type_;
};
}}} // apache::thrift::transport
#endif // #ifndef _THRIFT_TRANSPORT_TZMQCLIENT_H_

View file

@ -0,0 +1,64 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
import zmq
from cStringIO import StringIO
from thrift.transport.TTransport import TTransportBase, CReadableTransport
class TZmqClient(TTransportBase, CReadableTransport):
def __init__(self, ctx, endpoint, sock_type):
self._sock = ctx.socket(sock_type)
self._endpoint = endpoint
self._wbuf = StringIO()
self._rbuf = StringIO()
def open(self):
self._sock.connect(self._endpoint)
def read(self, size):
ret = self._rbuf.read(size)
if len(ret) != 0:
return ret
self._read_message()
return self._rbuf.read(size)
def _read_message(self):
msg = self._sock.recv()
self._rbuf = StringIO(msg)
def write(self, buf):
self._wbuf.write(buf)
def flush(self):
msg = self._wbuf.getvalue()
self._wbuf = StringIO()
self._sock.send(msg)
# Implement the CReadableTransport interface.
@property
def cstringio_buf(self):
return self._rbuf
# NOTE: This will probably not actually work.
def cstringio_refill(self, prefix, reqlen):
while len(prefix) < reqlen:
self.read_message()
prefix += self._rbuf.getvalue()
self._rbuf = StringIO(prefix)
return self._rbuf

View file

@ -0,0 +1,96 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include "TZmqServer.h"
#include <thrift/transport/TBufferTransports.h>
#include <boost/scoped_ptr.hpp>
using boost::shared_ptr;
using apache::thrift::transport::TMemoryBuffer;
using apache::thrift::protocol::TProtocol;
namespace apache { namespace thrift { namespace server {
bool TZmqServer::serveOne(int recv_flags) {
zmq::message_t msg;
bool received = sock_.recv(&msg, recv_flags);
if (!received) {
return false;
}
shared_ptr<TMemoryBuffer> inputTransport(new TMemoryBuffer((uint8_t*)msg.data(), msg.size()));
shared_ptr<TMemoryBuffer> outputTransport(new TMemoryBuffer());
shared_ptr<TProtocol> inputProtocol(
inputProtocolFactory_->getProtocol(inputTransport));
shared_ptr<TProtocol> outputProtocol(
outputProtocolFactory_->getProtocol(outputTransport));
shared_ptr<TMemoryBuffer> transport(new TMemoryBuffer);
processor_->process(inputProtocol, outputProtocol, NULL);
if (zmq_type_ == ZMQ_REP) {
uint8_t* buf;
uint32_t size;
outputTransport->getBuffer(&buf, &size);
msg.rebuild(size);
std::memcpy(msg.data(), buf, size);
(void)sock_.send(msg);
}
return true;
}
void TZmqMultiServer::serveOne(long timeout) {
boost::scoped_ptr<zmq::pollitem_t> items(setupPoll());
serveActive(items.get(), timeout);
}
void TZmqMultiServer::serveForever() {
boost::scoped_ptr<zmq::pollitem_t> items(setupPoll());
while (true) {
serveActive(items.get(), -1);
}
}
zmq::pollitem_t* TZmqMultiServer::setupPoll() {
zmq::pollitem_t* items = new zmq::pollitem_t[servers_.size()];
for (int i = 0; i < servers_.size(); ++i) {
items[i].socket = servers_[i]->getSocket();
items[i].events = ZMQ_POLLIN;
}
return items;
}
void TZmqMultiServer::serveActive(zmq::pollitem_t* items, long timeout) {
int rc = zmq::poll(items, servers_.size(), timeout);
if (rc == 0) {
return;
}
for (int i = 0; i < servers_.size(); ++i) {
if ((items[i].revents & ZMQ_POLLIN) != 0) {
// Should we pass ZMQ_NOBLOCK here to be safe?
servers_[i]->serveOne();
}
}
}
}}} // apache::thrift::server

View file

@ -0,0 +1,83 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#ifndef _THRIFT_SERVER_TZMQSERVER_H_
#define _THRIFT_SERVER_TZMQSERVER_H_ 1
#include <zmq.hpp>
#include <thrift/server/TServer.h>
namespace apache { namespace thrift { namespace server {
class TZmqServer : public TServer {
public:
TZmqServer(
boost::shared_ptr<TProcessor> processor,
zmq::context_t& ctx, const std::string& endpoint, int type)
: TServer(processor)
, processor_(processor)
, zmq_type_(type)
, sock_(ctx, type)
{
if(zmq_type_ == ZMQ_SUB) {
sock_.setsockopt(ZMQ_SUBSCRIBE, "", 0) ; // listen to all messages
sock_.connect(endpoint.c_str()) ;
}
else {
sock_.bind(endpoint.c_str());
}
}
bool serveOne(int recv_flags = 0);
void serve() {
while (true) {
serveOne();
}
}
zmq::socket_t& getSocket() {
return sock_;
}
private:
boost::shared_ptr<TProcessor> processor_;
int zmq_type_;
zmq::socket_t sock_;
};
class TZmqMultiServer {
public:
void serveOne(long timeout = -1);
void serveForever();
std::vector<TZmqServer*>& servers() {
return servers_;
}
private:
zmq::pollitem_t* setupPoll();
void serveActive(zmq::pollitem_t* items, long timeout);
std::vector<TZmqServer*> servers_;
};
}}} // apache::thrift::server
#endif // #ifndef _THRIFT_SERVER_TZMQSERVER_H_

View file

@ -0,0 +1,79 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
import logging
import zmq
import thrift.server.TServer
import thrift.transport.TTransport
class TZmqServer(thrift.server.TServer.TServer):
def __init__(self, processor, ctx, endpoint, sock_type):
thrift.server.TServer.TServer.__init__(self, processor, None)
self.zmq_type = sock_type
self.socket = ctx.socket(sock_type)
self.socket.bind(endpoint)
def serveOne(self):
msg = self.socket.recv()
itrans = thrift.transport.TTransport.TMemoryBuffer(msg)
otrans = thrift.transport.TTransport.TMemoryBuffer()
iprot = self.inputProtocolFactory.getProtocol(itrans)
oprot = self.outputProtocolFactory.getProtocol(otrans)
try:
self.processor.process(iprot, oprot)
except Exception:
logging.exception("Exception while processing request")
# Fall through and send back a response, even if empty or incomplete.
if self.zmq_type == zmq.REP:
msg = otrans.getvalue()
self.socket.send(msg)
def serve(self):
while True:
self.serveOne()
class TZmqMultiServer(object):
def __init__(self):
self.servers = []
def serveOne(self, timeout=-1):
self._serveActive(self._setupPoll(), timeout)
def serveForever(self):
poll_info = self._setupPoll()
while True:
self._serveActive(poll_info, -1)
def _setupPoll(self):
server_map = {}
poller = zmq.Poller()
for server in self.servers:
server_map[server.socket] = server
poller.register(server.socket, zmq.POLLIN)
return (server_map, poller)
def _serveActive(self, poll_info, timeout):
(server_map, poller) = poll_info
ready = dict(poller.poll())
for sock, state in ready.items():
assert (state & zmq.POLLIN) != 0
server_map[sock].serveOne()

View file

@ -0,0 +1,46 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
using System.Reflection;
using System.Runtime.CompilerServices;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
[assembly: AssemblyTitle("ZmqServer")]
[assembly: AssemblyDescription("Zmq Examples")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("The Apache Software Foundation")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("The Apache Software Foundation")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("1.0.*")]
// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.
//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")]

View file

@ -0,0 +1,60 @@
using System;
using System.Threading;
using Thrift.Protocol;
using ZMQ;
using ZmqServer;
using ZmqClient;
namespace ZmqServer
{
class MainClass
{
public static void Main (string[] args)
{
new Thread(Server.serve).Start();
Client.work();
}
static class Server{
public static void serve(){
StorageHandler s=new StorageHandler();
Storage.Processor p=new Storage.Processor(s);
ZMQ.Context c=new ZMQ.Context();
TZmqServer tzs=new TZmqServer(p,c,"tcp://127.0.0.1:9090",ZMQ.SocketType.PAIR);
tzs.Serve();
}
class StorageHandler:Storage.Iface{
int val=0;
public void incr(int amount){
val+=amount;
Console.WriteLine("incr({0})",amount);
}
public int get(){
return val;
}
}
}
static class Client{
public static void work()
{
Context ctx=new Context();
TZmqClient tzc=new TZmqClient(ctx,"tcp://127.0.0.1:9090",SocketType.PAIR);
TBinaryProtocol p=new TBinaryProtocol(tzc);
Storage.Client client=new Storage.Client(p);
tzc.Open();
Console.WriteLine(client.@get());
client.incr(1);
client.incr(41);
Console.WriteLine(client.@get());
}
}
}
}

View file

@ -0,0 +1,78 @@
using System;
using ZMQ;
using System.IO;
using Thrift.Transport;
namespace ZmqClient
{
public class TZmqClient : TTransport
{
Socket _sock;
String _endpoint;
MemoryStream _wbuf = new MemoryStream ();
MemoryStream _rbuf = new MemoryStream ();
void debug (string msg)
{
//Uncomment to enable debug
// Console.WriteLine (msg);
}
public TZmqClient (Context ctx, String endpoint, SocketType sockType)
{
_sock = ctx.Socket (sockType);
_endpoint = endpoint;
}
public override void Open ()
{
_sock.Connect (_endpoint);
}
public override void Close ()
{
throw new NotImplementedException ();
}
public override bool IsOpen {
get {
throw new NotImplementedException ();
}
}
public override int Read (byte[] buf, int off, int len)
{
debug ("Client_Read");
if (off != 0 || len != buf.Length)
throw new NotImplementedException ();
if (_rbuf.Length == 0) {
//Fill the Buffer with the complete ZMQ Message which needs to be(?!) the complete Thrift response
debug ("Client_Read Filling buffer..");
byte[] tmpBuf = _sock.Recv ();
debug (string.Format("Client_Read filled with {0}b",tmpBuf.Length));
_rbuf.Write (tmpBuf, 0, tmpBuf.Length);
_rbuf.Position = 0; //For reading
}
int ret = _rbuf.Read (buf, 0, len);
if (_rbuf.Length == _rbuf.Position) //Finished reading
_rbuf.SetLength (0);
debug (string.Format ("Client_Read return {0}b, remaining {1}b", ret, _rbuf.Length - _rbuf.Position));
return ret;
}
public override void Write (byte[] buf, int off, int len)
{
debug ("Client_Write");
_wbuf.Write (buf, off, len);
}
public override void Flush ()
{
debug ("Client_Flush");
_sock.Send (_wbuf.GetBuffer ());
_wbuf = new MemoryStream ();
}
}
}

View file

@ -0,0 +1,56 @@
using System;
using Thrift;
using Thrift.Server;
using Thrift.Transport;
using Thrift.Protocol;
using ZMQ;
using System.IO;
using System.Collections.Generic;
namespace ZmqServer
{
public class TZmqServer
{
Socket _socket ;
TProcessor _processor;
void debug (string msg)
{
//Uncomment to enable debug
// Console.WriteLine (msg);
}
public TZmqServer (TProcessor processor, Context ctx, String endpoint, SocketType sockType)
{
new TSimpleServer (processor,null);
_socket = ctx.Socket (sockType);
_socket.Bind (endpoint);
_processor = processor;
}
public void ServeOne ()
{
debug ("Server_ServeOne");
Byte[] msg = _socket.Recv ();
MemoryStream istream = new MemoryStream (msg);
MemoryStream ostream = new MemoryStream ();
TProtocol tProtocol = new TBinaryProtocol (new TStreamTransport (istream, ostream));
_processor.Process (tProtocol, tProtocol);
if (ostream.Length != 0) {
byte[] newBuf = new byte[ostream.Length];
Array.Copy (ostream.GetBuffer (), newBuf, ostream.Length);
debug (string.Format ("Server_ServeOne sending {0}b", ostream.Length));
_socket.Send (newBuf);
}
}
public void Serve ()
{
while (true)
ServeOne ();
}
}
}

View file

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>0.10.0</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>ZmqServer</RootNamespace>
<AssemblyName>ThriftZMQ</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileUpgradeFlags>
</FileUpgradeFlags>
<OldToolsVersion>3.5</OldToolsVersion>
<UpgradeBackupLocation />
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>0.10.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
<Externalconsole>true</Externalconsole>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<DebugType>none</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
<Externalconsole>true</Externalconsole>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="clrzmq, Version=2.1.0.0, Culture=neutral, processorArchitecture=x86">
<SpecificVersion>False</SpecificVersion>
<HintPath>.\clrzmq.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="Thrift, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\lib\csharp\Thrift.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Main.cs" />
<Compile Include="AssemblyInfo.cs" />
<Compile Include="TZmqServer.cs" />
<Compile Include="TZmqClient.cs" />
<Compile Include="..\gen-csharp\Storage.cs" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
<Visible>False</Visible>
<ProductName>Windows Installer 3.1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>

View file

@ -0,0 +1,42 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThriftZMQ", "ThriftZMQ.csproj", "{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thrift", "..\..\..\lib\csharp\src\Thrift.csproj", "{499EB63C-D74C-47E8-AE48-A2FC94538E9D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|Mixed Platforms = Debug|Mixed Platforms
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|Mixed Platforms = Release|Mixed Platforms
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Debug|Any CPU.ActiveCfg = Debug|x86
{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Debug|Mixed Platforms.Build.0 = Debug|x86
{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Debug|x86.ActiveCfg = Debug|x86
{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Debug|x86.Build.0 = Debug|x86
{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Release|Any CPU.ActiveCfg = Release|x86
{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Release|Mixed Platforms.ActiveCfg = Release|x86
{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Release|Mixed Platforms.Build.0 = Release|x86
{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Release|x86.ActiveCfg = Release|x86
{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Release|x86.Build.0 = Release|x86
{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|x86.ActiveCfg = Debug|Any CPU
{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.Build.0 = Release|Any CPU
{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,4 @@
service Storage {
oneway void incr(1: i32 amount);
i32 get();
}

View file

@ -0,0 +1,40 @@
#include <iostream>
#include <cstdlib>
#include <thrift/protocol/TBinaryProtocol.h>
#include "zmq.hpp"
#include "TZmqClient.h"
#include "Storage.h"
using boost::shared_ptr;
using apache::thrift::transport::TZmqClient;
using apache::thrift::protocol::TBinaryProtocol;
int main(int argc, char** argv) {
const char* endpoint = "tcp://127.0.0.1:9090";
int socktype = ZMQ_REQ;
int incr = 0;
if (argc > 1) {
incr = atoi(argv[1]);
if (incr) {
socktype = ZMQ_DOWNSTREAM;
endpoint = "tcp://127.0.0.1:9091";
}
}
zmq::context_t ctx(1);
shared_ptr<TZmqClient> transport(new TZmqClient(ctx, endpoint, socktype));
shared_ptr<TBinaryProtocol> protocol(new TBinaryProtocol(transport));
StorageClient client(protocol);
transport->open();
if (incr) {
client.incr(incr);
usleep(50000);
} else {
int value = client.get();
std::cout << value << std::endl;
}
return 0;
}

View file

@ -0,0 +1,36 @@
#!/usr/bin/env python
import sys
import time
import zmq
import TZmqClient
import thrift.protocol.TBinaryProtocol
import storage.ttypes
import storage.Storage
def main(args):
endpoint = "tcp://127.0.0.1:9090"
socktype = zmq.REQ
incr = 0
if len(args) > 1:
incr = int(args[1])
if incr:
socktype = zmq.DOWNSTREAM
endpoint = "tcp://127.0.0.1:9091"
ctx = zmq.Context()
transport = TZmqClient.TZmqClient(ctx, endpoint, socktype)
protocol = thrift.protocol.TBinaryProtocol.TBinaryProtocolAccelerated(transport)
client = storage.Storage.Client(protocol)
transport.open()
if incr:
client.incr(incr)
time.sleep(0.05)
else:
value = client.get()
print value
if __name__ == "__main__":
main(sys.argv)

View file

@ -0,0 +1,40 @@
#include "zmq.hpp"
#include "TZmqServer.h"
#include "Storage.h"
using boost::shared_ptr;
using apache::thrift::TProcessor;
using apache::thrift::server::TZmqServer;
using apache::thrift::server::TZmqMultiServer;
class StorageHandler : virtual public StorageIf {
public:
StorageHandler()
: value_(0)
{}
void incr(const int32_t amount) {
value_ += amount;
printf("value_: %i\n", value_) ;
}
int32_t get() {
return value_;
}
private:
int32_t value_;
};
int main(int argc, char *argv[]) {
shared_ptr<StorageHandler> handler(new StorageHandler());
shared_ptr<TProcessor> processor(new StorageProcessor(handler));
zmq::context_t ctx(1);
TZmqServer oneway_server(processor, ctx, "epgm://eth0;239.192.1.1:5555", ZMQ_SUB);
oneway_server.serve();
return 0;
}

View file

@ -0,0 +1,32 @@
#include <iostream>
#include <cstdlib>
#include <thrift/protocol/TBinaryProtocol.h>
#include "zmq.hpp"
#include "TZmqClient.h"
#include "Storage.h"
using boost::shared_ptr;
using apache::thrift::transport::TZmqClient;
using apache::thrift::protocol::TBinaryProtocol;
int main(int argc, char** argv) {
const char* endpoint = "epgm://eth0;239.192.1.1:5555";
int socktype = ZMQ_PUB;
int incr = 1;
if (argc > 1) {
incr = atoi(argv[1]);
}
zmq::context_t ctx(1);
shared_ptr<TZmqClient> transport(new TZmqClient(ctx, endpoint, socktype));
shared_ptr<TBinaryProtocol> protocol(new TBinaryProtocol(transport));
StorageClient client(protocol);
transport->open();
client.incr(incr);
usleep(50000);
return 0;
}

View file

@ -0,0 +1,43 @@
#include "zmq.hpp"
#include "TZmqServer.h"
#include "Storage.h"
using boost::shared_ptr;
using apache::thrift::TProcessor;
using apache::thrift::server::TZmqServer;
using apache::thrift::server::TZmqMultiServer;
class StorageHandler : virtual public StorageIf {
public:
StorageHandler()
: value_(0)
{}
void incr(const int32_t amount) {
value_ += amount;
}
int32_t get() {
return value_;
}
private:
int32_t value_;
};
int main(int argc, char *argv[]) {
shared_ptr<StorageHandler> handler(new StorageHandler());
shared_ptr<TProcessor> processor(new StorageProcessor(handler));
zmq::context_t ctx(1);
TZmqServer reqrep_server(processor, ctx, "tcp://0.0.0.0:9090", ZMQ_REP);
TZmqServer oneway_server(processor, ctx, "tcp://0.0.0.0:9091", ZMQ_UPSTREAM);
TZmqMultiServer multiserver;
multiserver.servers().push_back(&reqrep_server);
multiserver.servers().push_back(&oneway_server);
multiserver.serveForever();
return 0;
}

Some files were not shown because too many files have changed in this diff Show more