TomcatExpert

How Apache Tomcat Implemented WebSocket

posted by fhanik on May 1, 2012 07:13 AM

With the Apache Tomcat 7.0.27 release, the Apache Tomcat team introduced a WebSocket implementation. In a previous post, we took a look at what the WebSocket implementation means, including what benefits and limitations they present. Today, we will discuss specifically how WebSocket is implemented in Apache Tomcat 7.

Since WebSocket is a protocol sent over TCP after an initial HTTP handshake, you could effectively implement WebSocket using Tomcat’s Comet implementation. There is a back port to Tomcat 6 suggested that does exactly that with very minor changes.

The Apache Tomcat team however decided to go with a more substantial implementation with changes to the core of Tomcat’s network and protocol implementation. The reason for this was memory and scalability based. If Tomcat can recycle the HttpServletRequest/Response objects after the initial handshake, each WebSocket connection will take up less memory in the Java heap. It also opens up the Tomcat container for other future protocols that utilize the HTTP Upgrade feature.

The WebSocket implementation from an API standpoint is fairly straightforward. You really can only do two things:

  1. Send messages
  2. Receive messages

This means you have to implement a mechanism to send a message based on a specific action in your application and implement a callback listener when a message arrives from a client.

To get yourself familiarized with the best way is to walk through some of the examples within Tomcat. We will demonstrate the Chat example, and dive into the API a little bit deeper.

To get started with WebSocket you will have to extend Tomcat’s WebSocket class.

Step 1 – extend the WebSocketServlet class

public class ChatWebSocketServlet extends WebSocketServlet

Since it’s a servlet, you must map it to a URL 

<servlet>
<servlet-name>wsChat</servlet-name>
<servlet-class>
websocket.chat.ChatWebSocketServlet
<servlet-class>
</servlet> 
<servlet-mapping>
<servlet-name>wsChat</servlet-name>
<url-pattern>/websocket/chat</url-pattern>
</servlet-mapping>

In this step we have touched on several important aspects

  1. Since this is a servlet, Tomcat decides if a HTTP request is a WebSocket request based on the URL that you have mapped to your servlet in web.xml or using annotations.
  2. Your class has to import org.apache.catalina.websocket.WebSocketServlet
  3. You can protect access to this using standard methods (servlet security) or frameworks like Spring Security.
  4. It’s a servlet. Lifecycle events, initialization and request parameters, cookies, session data, all the goodies you already know how to use are available to you.

That’s the easy part, let’s move on to using the actual API to receive messages.

Step 2 – Implementing a message listener

Extending the WebSocketServlet requires you to implement the

protected StreamInbound createWebSocketInbound(String subProtocol) {

return new ChatMessageInbound();

}

method. The StreamInbound class has a few onXXX methods that can be implemented to be notified of events. The two required methods are

protected void onBinaryData(InputStream is);
protected void onTextData(Reader r);

 

WebSocket messages can come in binary form, onBinaryData, or text form, onTextData, and your application may choose to utilize one or both of these methods. Once you’ve created a class that implements both these methods your application is ready to receive messages.

An example implementation would look like this (only text data)

private final class ChatMessageInbound extends MessageInbound {
 
@Override
protected void onBinaryMessage(ByteBuffer message)
throws IOException {
//this application does not expect binary data
throw new UnsupportedOperationException(
"Binary message not supported.");
}
 
@Override
protected void onTextMessage(CharBuffer message) throws IOException {
String msg = message.toString();
//modify the message by adding a timestamp
msg = “(“ + System.currentTimeMillis()+”) “+ msg;
broadcast(msg);
}
 
private void broadcast(String message) {
//write some code to process the message
}
 
 
 

If you wish to be notified when a WebSocket connection is opened or closed, simply override the onOpen and onClose methods

@Override
protected void onOpen(WsOutbound outbound);
 
@Override
protected void onClose(int status);

In the Chat example, these two methods track when Chat clients arrive or leave the chat.

 

Step 3 – Writing data to the client

Writing data is pretty straightforward. Your StreamInbound implementation will have a reference to the sender component, WsOutbound. You simply retrieve it by calling

myStreamInbound.getWsOutbound()

at that point you can send either binary

public void writeBinaryData(int b);
public void writeBinaryMessage(ByteBuffer msgBb);

or textual data to the client

public void writeTextData(char c);
public void writeTextMessage(CharBuffer msgBb);

So why do we have two methods for sending textual and two methods for sending binary data? The answer is one of them is streaming, the other is to send a buffered message. When streaming messages, meaning you are using one of these two methods

public void writeTextData(char c);
public void writeBinaryData(int b);

These methods are mutually exclusive. Don’t call both of these methods and expect both binary and textual data to be sent. When you’re done streaming, simply call

public synchronized void flush() throws IOException;

If you previously called writeTextData(char c) you can switch to binary data after calling flush(). Calling flush() completes the WebSocket message. A message can be sent down to the client in multiple frames (or fragments), a frame being a WebSocket defined set of data. When you use the

public void writeTextMessage(CharBuffer msgBb);
public void writeBinaryMessage(ByteBuffer msgBb);

methods each set of data gets transferred as a message.

In the Apache Tomcat WebSocket Chat example, each time a message is received, it broadcasts that message to the other clients as a separate message.

private void broadcast(String message) {
for (ChatMessageInbound connection : connections) {
try {
CharBuffer buffer = CharBuffer. wrap(message); connection.getWsOutbound().writeTextMessage(buffer);
} catch (IOException ignore)
// Ignore
}
     }
}

Step 4 – Closing the connection to the client

The one additional piece of important information is that there are two ways a channel can close in both a “clean” and a “not clean” manner. Clean implies that a handshake has been completed over TCP, using the

public synchronized void close(int status, ByteBuffer data)

method when initiated on the server. Not clean closure means that the TCP connection was disconnected or aborted prior to the close handshake taking place. To be notified of when a channel has been closed by the client or uncleanly, you override with:

@Override
protected void onClose(int status);

Summary

Tomcat’s WebSocket implementation utilizes servlets as the URL based endpoint for WebSocket communications and can utilize all the features that are available within a servlet. A developer implementing a WebSocket application can receive and send messages in the org.apache.catalina.websocket.StreamInbound and org.apache.catalina.websocket.WsOutbound classes. Messages can be streamed or sent as entire messages using the writeTextMessage, writeTextData, writeBinaryMessage, writeBinaryData methods. The first released version of WebSocket in Apache Tomcat was released with Apache Tomcat 7.0.27 and the above Chat example can be found in the webapps/examples/websocket folder of the Apache Tomcat installation.

We encourage Tomcat users to try it out, and if you have feedback or issues please address them on the official Apache Tomcat user mailing lists.

Filip Hanik is a Senior Software Engineer for the SpringSource Division of VMware, Inc. (NYSE: VMW) and a key participant in the company's Apache Tomcat initiatives. Filip brings 15 years of extensive experience in architecture, design and development of distributed application frameworks and containers and is recognized for his top-quality system development skills and continuous participation of Open Source development projects. Filip is an Apache Software Foundation member and a committer to the Apache Tomcat project where he is a leading authority on Tomcat clustering and a key contributor to the core of the platform. Filip has made contributions to software initiatives for Walmart.com, Sony Music, France Telecom and has held a variety of senior software engineering positions with technology companies in both the United States and Sweden. He received his education at Chalmers University of Technology in Gothenburg, Sweden where he majored in Computer Science and Computer Engineering.

Comments

"connections" variable

In method broadcast() in Step3 above you loop on a variable called "connections" - where do you get this from? Thanks!

Paste this and GO! in you

Paste this and GO! in you browser while tomcat is running: http://localhost:8084(change to your port)/examples/websocket/

I would recommend my profile

I would recommend my profile is important to me, I invite you to discuss this topic. The Woman Men Adore Review

Hmm… I interpret blogs on a

Hmm… I interpret blogs on a analogous issue, however i never visited your blog. I added it to populars also i’ll be your faithful primer. The Psystrology Method Review

sl786982

You done certain great focuses there. I did an inquiry on the subject and discovered about all persons will concur with your site. Lingerie for London models

sl786982

I would recommend my profile

I would recommend my profile is important to me, I invite you to discuss this topic. Signs it is Time to end a Relationship

I should say only that its

I should say only that its awesome! The blog is informational and always produce amazing things. Obsession Phrases Review

These you will then see the

These you will then see the most important thing, the application provides you a website a powerful important internet page: expired domains with usa traffic

sl786982

Along these lines, I might want you that you continue proceeding with your work on this article. Entradas olimpiadas 2016

sl786982

For this web site, you will

For this web site, you will see our account, remember to go through this info. elementos seguridad

found

Ok found the full-servlet code! Awesome stuff, well done!

sl786982

Wonderful posting, Thanks a ton to get spreading The following awareness. Wonderfully authored posting, doubts all of blog owners available precisely the same a higher standard subject material just like you, online has got to be improved site. I highly recommend you stay the best! original binary option robot

sl786982

sl786982

Yes i am completely concurred with this article and i simply need say this article is extremely decent and exceptionally useful article. binary options trading signals

sl786982

broadcasting a message through a specific websocket in java

Thanks for the tutorial. I got my app to work but I need help with retrieving an object of a specific websocket so that i can brodcast a message to it, within a java Spring Controller for example:
I have three sockets that are created by url-parttened in the web.xml as
/one
/two
/three
NB: these are in three different servlets
This means that I would have 3 websockets that users have choice to connect to. Also note that I am using Spring MVC 3.

My Question: When a user posts a form that has data going to the database & then upon successfully persisting the data, I would want to use a Controller to broadcast the message to websocket "one" and not the other two. How do I achieve that?

Your assistence is well appreciated. :)

How do you access the request parameters ?

I can only see the reference of HttpServletRequest in createWebSocketInbound. How can I access request parameters in the onTextMessage event ?

How To Debt Negotiation

The most interesting text on this interesting topic that can be found on the net ...
learn about debt management

May I just say what a relief

May I just say what a relief to discover somebody that actually knows what they are talking about online. You certainly know how to bring an issue to light and make it important. More and more people have to read this and understand this side of the story. I was surprised that you're not more popular because you definitely have the gift.
Mortgage Broker Calgary

jackson

how to get subscribers
The online world is usually bogged decrease having untrue information sites without the need of authentic meaning even so the write-up seemed to be excellent in addition to worthwhile this understand. Appreciate it intended for giving that by himself.
buy comments

GAME HACK

hungry shark evolution cheat Acknowledges for penmanship such a worthy column, I stumbled beside your blog besides predict a handful advise. I want your tone of manuscript... cheat clash of clans android

Appreciate it intended for giving that by himself.

Obat Kista Sakit kista tidak bisa menyebar ke bagian organ tubuh lain.
obat gagal ginjal Dalam tempo satu tahun proses pengobatan gagal ginjal Pak Sigit sudah menghabiskan sebanyak 150 juta rupiah.
obat miom ancaman keguguran karna miom yang membesar akan mendorong janin.

Obat rematik Tradisional

let it be the one Obat Rematik Tradisional

Jelly Gamat

Harga Jelly Gamaat

Ace Maxs

Pe

obat kanker payudara Tahukah

obat kanker payudara Tahukah anda arti dari dari Kanker Payudara?
obat stroke Pemulihan Penyakit Stroke menggunakan amazon Plus Obat Tradisional Alami.
obat kanker serviks Faktor alami sebagai pelopor kanker leher rahim adalah umur lebih dari 40 tahun.
obat kanker prostat Penyakit Kanker Prostat adalah suatu penyakit kanker yang mana berkembang di bagian prostat.

I like viewing web sites

I like viewing web sites which comprehend the price of delivering the excellent useful resource free of charge. I truly adored reading your posting. Thank you! download Text Your Ex Back

Davis

I prefer states it all has written the third blog page concerning dissertation penning. Previously I just launched, I just would always worry about penning dissertations. I did so n't need in order to a specific thing average. This unique replaced when real I just man-ed all the way up not to mention has written your to begin with basically l explore it's i'm all over this!
Pro DJ

Get instagram followers

You could buy Instagram followers to assist you to increase your landscapes. Instagram is regarded as the leading photo posting online websites found on the World Wide Web. It is also made use of by end users to display situation their style and creativity. People may take an image, submit it, utilize virtual screens, and after that write about it on various social bookmarking internet websites like Face book, Twitter and Tumbler and also to Instagram itself.

Buy instagram followers cheap
Buy likes on instagram
Buy instagram followers cheap
Get instagram likes

each WebSocket connection

each WebSocket connection will take up less memory in the Java heap.cccam server

What a really awesome post

What a really awesome post this is. Truly, one of the best posts I've ever witnessed to see in my whole life. Wow, just keep it up. upresults.nic.in

Its a great pleasure reading

Its a great pleasure reading your post.Its full of information I am looking for and I love to post a comment that "The content of your post is awesome" Great work.Diabetes Destroyer

On this page, you'll see my

On this page, you'll see my profile, please read this information. quality management certification

Welcome to the party of my

Welcome to the party of my life here you will learn everything about me. cake bakeries in houston

A good blog always comes-up

A good blog always comes-up with new and exciting information and while reading I have feel that this blog is really have all those quality that qualify a blog to be a one.I wanted to leave a little comment to support you and wish you a good continuation. Wishing you the best of luck for all your blogging efforts. Rocket Spanish

Writing with style and

Writing with style and getting good compliments on the article is quite hard, to be honest.But you've done it so calmly and with so cool feeling and you've nailed the job. This article is possessed with style and I am giving good compliment. Best! Language of Desire

In this article understand

In this article understand the most important thing, the item will give you a keyword rich link a great useful website page: What Men Secretly Want

In this case you will begin

In this case you will begin it is important, it again produces a web site a strong significant internet site: The Instant Switch

These websites are really

These websites are really needed, you can learn a lot. Talk To His Heart

It's superior, however ,

It's superior, however , check out material at the street address. The Woman Men Adore

This is very interesting, but

This is very interesting, but it is necessary to click on this link: Ex Factor Guide Review

I can give you the address

I can give you the address Here you will learn how to do it correctly. Read and write something good. The Red Smoothie Detox Factor Review

On this page, you'll see my

On this page, you'll see my profile, please read this information. Wrap Him Around Your Finger Review

For many people this is

For many people this is important, so check out my profile: the language of lust

On this subject internet

On this subject internet page, you'll see my best information, be sure to look over this level of detail. The Respect Principle

Being a Novice, I will be

Being a Novice, I will be once and for all checking out on the web regarding posts which can be regarding assist with myself. Many thanks.
ClubFlyers

NILE 7

شركة تنظيف كنب بالدمام
شركة جلى بلاط بالدمام
شركة تنظيف فلل بالدمام
شركة تنظيف شقق بالدمام
شركة تنظيف سجاد بالدمام
شركة تنظيف مجالس بالدمام
شركة عزل خزانات بالدمام
شركة عزل مائى بالدمام
شركة كشف تسربات بدون تكسير بالدمام
شركة تسليك مجارى بالدمام
شركة شفط بيارات بالدمام
شركة رش مبيدات بالدمام
شركة نقل عفش بالدمام
شركة تخزين عفش بالدمام
شركة تنظيف منازل بالدمام
شركة مكافحة حشرات بالدمام
شركة تنظيف كنب بالدمام
شركة تنظيف منازل بالدمام
شركة تنظيف شقق بالدمام
شركة تنظيف فلل بالدمام
شركة مكافحة حشرات بالاحساء
شركة تسليك مجارى بالجبيل
شركة تنظيف موكيت بالدمام
شركة مكافحة الصراصير بالخبر
شركة مكافحة النمل الابيض بالاحساء
شركة رش مبيدات بالاحساء
شركة نقل اثاث بالدمام
شركة نقل عفش بالدمام
شركة تنظيف خزانات بالدمام
شركة كشف تسربات المياه بالدمام
شركة تخزين اثاث بالدمام
شركة عزل اسطح بالدمام
شركة تنظيف كنب بالدمام
شركة تنظيف بالدمام
شركة تنظيف فلل بالدمام
شركة تنظيف شقق بالدمام
شركة تنظيف موكيت بالدمام
شركة تنظيف مجالس بالدمام
شركة تنظيف خزانات بالدمام
شركة عزل اسطح بالدمام
شركة كشف تسربات المياه بالدمام
شركة تسليك مجارى بالدمام
شركة تنظيف بيارات بالدمام
شركة رش مبيدات بالدمام
شركة نقل اثاث بالدمام
شركة تخزين اثاث بالدمام
شركة تنظيف منازل بالدمام
شركة مكافحة حشرات بالدمام
شركة مكافحة الفئران بجدة
شركة تخزين عفش بجدة
شركة تسليك مجارى بجدة
شركة عزل خزانات بجدة
شركة رش مبيدات بجدة
شركة مكافحة حشرات بجدة
شركة تنظيف شقق بجدة
شركة تنظيف بجدة
شركة كشف تسربات المياة بجدة
نقل عفش بجدة
نقل عفش بمكة
نقل عفش بالطائف
شركة تخزين اثاث بجدة
شركة تخزين اثاث بمكة
شركة تخزين اثاث بالطائف
شركة تنظيف خزانات بالدمام
شركة تسليك مجاري بالخبر
شركة رش مبيدات بالدمام
شركة مكافحة حشرات بالخبر
شركة تنظيف شقق بالدمام
شركة تنظيف منازل بالدمام
شركة تنظيف فلل بالدمام
شركة تنظيف موكيت بالدمام
شركة تخزين اثاث بالدمام
شركة كشف تسربات المياة بالدمام
شركة عزل اسطح بالدمام
شركة نقل اثاث بحفر الباطن

devidmiller5060

I was very pleased to find this site.I wanted to thank you for this great read!! I definitely enjoying every little bit of it and I have you bookmarked to check out new stuff you post.
rims for sale

devidmiller5060

Easily, the article is actually the best topic on this registry related issue. I fit in with your conclusions and will eagerly look forward to your next updates. Just saying thanks will not just be sufficient, for the fantasti c lucidity in your writing. I will instantly grab your rss feed to stay informed of any updates.
best memory foam mattress

marwa

شركة تخزين اثاث بالطائف
شركة تنظيف شقق بالطائف
شركة تنظيف فلل بالطائف
شركة تنظيف منازل بالطائف
شركة رش مبيدات بالطائف
شركة نقل اثاث بالطائف
شركة تسليك مجارى بالطائف
شركة تنظيف بخميس مشيط
شركة تنظيف بيارات بالطائف
شركة تنظيف مجالس بالطائف
شركة عزل اسطح بالطائف
شركة مكافحة حشرات بالطائف
شركة تنظيف بالطائف
شركة تنظيف خزانات بالطائف
شركة تنظيف كنب بالطائف
شركة تنظيف كنب بخميس مشيط
شركة تنظيف موكيت بالطائف
شركة كشف تسربات المياه بالطائف
شركة تسليك مجارى بخميس مشيط
شركة تنظيف بيارات بخميس مشيط
شركة تنظيف شقق بخميس مشيط
شركة تنظيف فلل بخميس مشيط
شركة نقل اثاث بخميس مشيط
شركة تخزين اثاث بخميس مشيط
شركة تنظيف شقق بأبها
شركة تنظيف فلل بأبها
شركة تنظيف منازل بخميس مشيط
شركة رش مبيدات بخميس مشيط
شركة مكافحة حشرات بخميس مشيط
شركة تنظيف خزانات بخميس مشيط
شركة تنظيف كنب بأبها
شركة تنظيف مجالس بخميس مشيط
شركة تنظيف موكيت بخميس مشيط
شركة عزل اسطح بخميس مشيط
شركة كشف تسربات المياه بخميس مشيط
شركة تنظيف مجالس بأبها
شركة تنظيف موكيت بأبها
شركة تنظيف خزانات بأبها
شركة عزل اسطح بأبها
شركة كشف تسريبات المياه بأبها
شركة تسليك مجارى بأبها
شركة تنظيف منازل بأبها
شركة مكافحة حشرات بأبها
شركة رش مبيدات بأبها
شركة نقل اثاث بأبها
شركة تخزين اثاث بأبها
شركة تنظيف بيارات بأبها
شركة تسليك مجاري بخميس مشيط
شركة تنظيف بخميس مشيط
شركة تنظيف بيارات بخميس مشيط
شركة تنظيف خزانات بخميس مشيط
شركة تنظيف شقق بخميس مشيط
شركة تنظيف فلل بخميس مشيط
شركة تنظيف مجالس بخميس مشيط
شركة عزل أسطح بخميس مشيط
شركة كشف تسربات المياه بخميس مشيط
شركة تنظيف كنب بخميس مشيط
شركة تنظيف موكيت بخميس مشيط
شركة تنظيف منازل بخميس مشيط
شركة نقل اثاث بخميس مشيط
شركة تخزين أثاث بخميس مشيط
شركة رش مبيدات بخميس مشيط
شركة مكافحة حشرات بخميس مشيط
شركة تنظيف بأبها
شركة تنظيف شقق بأبها
شركة تنظيف فلل بأبها
شركة تخزين أثاث بـأبها
شركة تسليك مجارى بأبها
شركة تنظيف بأبها
شركة تنظيف منازل بأبها
شركة عزل اسطح بأبها
شركة نقل اثاث بأبها
شركة تنظيف بيارات بأبها
شركة تنظيف موكيت بأبها
شركة رش مبيدات بأبها

شركة كشف تسربات المياه بأبها
شركة تنظيف بالطائف
شركة تنظيف شقق بالطائف
شركة تنظيف فلل بالطائف
شركة تنظيف كنب بالطائف
شركة تنظيف مجالس بالطائف
شركة تنظيف موكيت بالطائف
شركة تنظيف خزانات بالطائف
شركة عزلاسطح بالطائف
شركة كشف تسريبات المياه بالطائف
شركة تسليك مجارى بالطائف
شركة تنظيف بيارات بالطائف
شركة رش مبيدات بالطائف
شركة نقل اثاث بالطائف
شركة تخزين اثاث بالطائف
شركة مكافحة حشرات بالطائف
شركة تنظيف منازل بالطائف
شركة مكافحة حشرات بأبها
شركة تنظيف خزانات بأبها
شركة تنظيف مجالس بأبها
شركة تنظيف كنب بأبها

I recommend only good and

I recommend only good and reliable information, so see it: Law of Devotion Review

mostafashehata

شركة تنظيف بالرياض
شركة تنظيف شقق بالرياض
شركة تنظيف فلل بالرياض
شركة تنظيف بيارات بالرياض
شركة تنظيف منازل بالرياض
شركة نقل أثاث بالرياض
شركة تسليك مجاري بالرياض
شركة عزل أسطح بالرياض
شركة كشف تسربات المياه بالرياض
شركة تخزين أثاث بالرياض
شركة تنظيف خزانات بالرياض
شركة تنظيف مجالس بالرياض
شركة تنظيف موكيت بالرياض
شركة رش مبيدات بالرياض
شركة مكافحة حشرات بالرياض
شركة تخزين أثاث بخميس مشيط
شركة تسليك مجاري بخميس مشيط
شركة تنظيف بخميس مشيط
شركة تنظيف بيارات بخميس مشيط
شركة تنظيف خزانات بخميس مشيط
شركة تنظيف شقق بخميس مشيط
شركة تنظيف فلل بخميس مشيط
شركة تنظيف مجالس بخميس مشيط
شركة تنظيف منازل بخميس مشيط
شركة تنظيف موكيت بخميس مشيط
شركة رش مبيدات بخميس مشيط
شركة عزل أسطح بخميس مشيط
شركة كشف تسربات المياه بخميس مشيط
شركة مكافحة حشرات بخميس مشيط
شركة نقل أثاث بخميس مشيط
شركة تنظيف بيارات بالمدينة المنورة
شركة مكافحة حشرات بالمدينة المنورة
شركة نقل اثاث بالمدينة المنورة
شركة تخزين اثاث بالمدينة المنورة
شركة تنظيف منازل بالمدينة المنورة
شركة رش مبيدات بالمدينة المنورة
شركة تنظيف بالمدينه المنورة
شركة تنظيف فلل بالمدينة المنورة
شركة تنظيف شقق بالمدينة المنورة
شركة تنظيف موكيت بالمدينة المنورة
شركة تنظيف مجالس بالمدينة المنورة
شركة تنظيف خزانات بالمدينة المنورة
شركة عزل اسطح بالمدينة المنورة
شركة كشف تسربات المياه بالمدينة المنورة
شركة تسليك مجارى بالمدينة المنورة
شركة تنظيف بجدة
شركة تنظيف فلل بجدة
شركة تنظيف شقق بجدة
شركة تنظيف مجالس بجدة
شركة تنظيف موكيت بجدة
شركة تنظيف خزانات بجدة
شركة عزل اسطح بجدة
شركة كشف تسربات المياه بجدة
شركة تسليك مجارى بجدة
شركة تنظيف بيارات بجدة
شركة رش مبيدات بجدة
شركة نقل اثاث بجدة
شركة تخزين اثاث بجدة
شركة تنظيف منازل بجدة
شركة مكافحة حشرات بجدة
شركة تنظيف بمكة
شركة تنظيف فلل بمكة
شركة تنظيف شقق بمكة
شركة تنظيف موكيت بمكة
شركة تنظيف بيارات بمكة
شركة رش مبيدات بمكة
شركة نقل اثاث بمكة
شركة تخزين اثاث بمكة
شركة تنظيف منازل بمكة
شركة مكافحة حشرات بمكة
شركة عزل اسطح بمكة
شركة تسليك مجاري بمكة
شركة كشف تسربات بمكة
شركة تنظيف خزانات بمكة
شركة تنظيف مجالس بمكة
شركة عزل اسطح بالطائف
شركة كشف تسربات المياه بالطائف
شركة تسليك مجارى بالطائف
شركة تنظيف بيارات بالطائف
شركة رش مبيدات بالطائف
شركة نقل اثاث بالطائف
شركة تخزين اثاث بالطائف
شركة تنظيف منازل بالطائف
شركة مكافحة حشرات بالطائف
شركة تنظيف بالطائف
شركة تنظيف فلل بالطائف
شركة تنظيف شقق بالطائف
شركة تنظيف موكيت بالطائف
شركة تنظيف مجالس بالطائف
شركة تنظيف خزانات بالطائف
شركة تنظيف منازل بابها
شركة مكافحة حشرات بابها
شركة رش مبيدات بابها
شركة عزل اسطح بابها
شركة كشف تسربات المياه بابها
شركة تسليك مجارى بابها
شركة تنظيف بيارات بابها
شركة تنظيف بابها
شركة تنظيف فلل بابها
شركة تنظيف شقق بابها
شركة تنظيف موكيت بابها
شركة تنظيف مجالس بابها
شركة تنظيف خزانات بابها
شركة نقل اثاث بابها
شركة تخزين اثاث بابها
شركة نقل اثاث بالدمام
شركة نقل اثاث بجدة
شركة مكافحة حشرات بالدمام
شركة مكافحة حشرات بجدة

This is very significant, and

This is very significant, and yet necessary towards just click this unique backlink. video editing

IMTI

without the need of authentic meaning even so the write-up seemed to be excellent in addition to worthwhile this understand. Appreciate it intended for giving that by himself.. Loft conversions ealing

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.